Contents

ADVANSYS

Formativ

GroupWise Customization Made Easy!

Programmer's Guide

This document guides you through the key issues in developing applications for Novell GroupWise using Advansys Formativ 1.6.

Advansys Formativ Programmers Guide

Information in this document is subject to change without notice. The example companies, products and people are purely fictitious. Without limiting the rights under copyright, no part of this document may be reproduced, stored or introduced into a retrieval system, or transmitted in any form without prior written approval of Advansys corporation.

Advansys may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering the subject matter in this document. Except as expressly provided in any written license agreement from Advansys, the furnishing of this document does not give you any license to these patents, trademarks, copyrights or other intellectual property.

Copyright © 2003 Advansys Pty Limited. All rights reserved.

Formativ is a trademark of Advansys Pty Limited in Australia and other countries.

GroupWise is a trademark of Novell Inc.

Visual Basic Script is a trademark of Microsoft Corporation.


Preface

The Advansys Formativ Programmer's Guide describes how to use the applications and facilities within Formativ to build custom GroupWise solutions. This guide is the definitive resource for developers who are creating custom solutions with Advansys Formativ and GroupWise. It should be read in conjunction with the Formativ Language Guide, Microsoft's Visual Basic Script documentation and Novell's Object and Admin API documentation. Links to those references can be found here.

Formativ uses an extended version of Microsoft Visual Basic Script as its applet programming language. If you know how to work with Microsoft Visual Basic Script, you can build on this knowledge easily to customize Novell GroupWise. If you are not familiar with Visual Basic Script, this guide will get you started. However, you will still need to access the various Visual Basic Script resources documented below to get the most out of the product.

Who should use this guide?

This guide has been written for developers. Developers form a large and diverse group. We use the term developer to include someone who wishes to do something as simple as automatically type some text into a GroupWise message, or create a new button on a toolbar, through to someone who wishes to build complex vertical market solutions for GroupWise using the Formativ environment.

This document is not for everybody. In order to cover the amount of information required adequately, we have had to make assumptions about your level of knowledge. You may benefit from first using one of the excellent introductory resources mentioned later in this document. Once you are happy that you have a sound grip of the basics, you can return to this guide.

What does this guide cover?

The purpose of this document is to guide you through the many facets of developing solutions using the Formativ environment. As the Formativ applet language is based on Microsoft Visual Basic Script (VBS), we assume you are comfortable with VBS and that you understand the concept of data types, variable scoping, functions and subroutines. We also assume you have a basic knowledge of the Novell GroupWise 5.5/6.x Windows client. If you are not comfortable with these topics, please refer to the appropriate resources, then return to this guide.


Code Samples and Programming Style

This document contains many code samples you can use to experiment with the concepts and ideas presented. In addition, Formativ Admin ships with a number of applets that represent solutions to real world problems. The example applets can be found in the \Examples directory under the Formativ directory (C:\Program Files\Advansys\Formativ\Examples).

This document, and the applet samples that ship with Formativ use the following coding conventions:

  • Keywords appear with an initial letter capitalized. Concatenated words may contain other capital letters. Variables appear in mixed case. Constants appear in uppercase.

    •

    Dim objGroupWise

    Const TEMPLATE_PATH = "C:\Templates\"

    Set objGroupWise = GetGroupWiseObject

  • In full procedures, all variables are declared locally, or are listed with an initialization procedure that declares public variables.

  • An apostrophe (') introduces a comment:

    •

    ' This is a comment in the source code

    Dim objMessage ' This is a comment on the same line as some source

  • Control-flow blocks and statements in Sub and Function procedures are indented:

    •

    Sub Main(Client, GWEvent)

    Dim Msg

    Set Msg = GroupWise.ComposingItem

    if Msg is Nothing then

    MsgBox("No composing item available")

    else

    ' Insert your code here

    Set Msg = nothing

    end if

    End Sub

  • Formativ applets are case insensitive. Capitalization of keywords, intrinsic functions, language elements and variable names is not required. However, we recommend you adopt a standard and apply it throughout your code.


Other Resources

There are many excellent resources available for you to accelerate your proficiency with Formativ. Formativ also exposes many of the GroupWise programming APIs via applet commands, so there are many Novell and third party resources that are excellent sources of information. Some of these are listed below:

  • Advansys Formativ Language Guide

    • This document details all of the extensions added to the Visual Basic Script language that allow you to interact with GroupWise. It details the objects available to automate the GroupWise client, access the GroupWise message store, and build interactive dialogs and forms.

  • Advansys Formativ Users Guide

    • This document details how to use the Formativ environment. It describes installation, configuration and operation. It covers how to write a new applet and how to integrate that applet with the GroupWise client.

  • Advansys Formativ Administrators Guide

    • This document details how to administer Formativ using Novell NDS. It covers planning, installation, configuration and operation.

  • Advansys Formativ Web Site

    • The Advansys Formativ Web site is the best source for the latest information about the product. You can access more samples, documentation, updates and news about Formativ, including product updates and fixes.

  • Advansys Formativ Business Solutions Pack

    • The Advansys Formativ Business Solutions Pack is a collection of pre-written applets that are installed as part of Formativ. They represent complete working solutions to common GroupWise enhancement requests. By default, the Business Solutions Pack Applets are installed to C:\Program Files\Advansys\Formativ\Local. These applets are supported by Advansys.

  • Advansys Formativ Example Applets

    • A wide variety of example applets are installed by default to C:\Program Files\Advansys\Formativ\Examples. These applets demonstrate a wide variety of applet techniques, and illustrate the type of solutions you can develop using Formativ. Some of the examples are complete solutions, while others are simple examples of specific techniques. These applets are not supported by Advansys.

  • Microsoft Visual Basic Script Users Guide

    • This is the best resource for Microsoft Visual Script programming. As Formativ applets are based on an extended version of Visual Basic Script 5.0, everything you read in the document applies to Formativ. This is the best resource if you have any questions at all about the Visual Basic Script language, and it covers all Visual Basic Script fundamentals.

  • Microsoft Visual Basic Script Language Reference

    • This Microsoft document contains the complete reference to the Visual Basic Script language.

  • Microsoft Visual Basic Script File System Object Guide

    • This is the definitive reference point for Microsoft's File system object. This object is used extensively in the Formativ example applets, and is required to perform any file-based operations in an applet.

  • Microsoft Visual Basic Script Regular Expressions Guide

    • This Microsoft document details how to use regular expressions in Visual Basic Script.

  • Microsoft Visual Basic Script FAQ

    • This Microsoft document contains the answers to many frequently asked questions about Visual Basic Script. It is a good reference for any general questions regarding the language. Note that references to using Visual Basic Script within HTML do not apply to Formativ.

  • Novell GroupWise Object API documentation

    • This online documentation, supplied and maintained by Novell, details the GroupWise Object API, which provides full access to the GroupWise message store. Advansys Formativ exposes the entire Object API, unchanged, via the Formativ applet language. Use this reference to learn about the Object API, and how you can use it directly within your Formativ applets.

  • Novell Administrative Objects API documentation

    • This online documentation, supplied and maintained by Novell, details the GroupWise Administrative Objects API, which provides full access to GroupWise administrative functions, such as adding new users and obtaining information about your GroupWise system. Advansys Formativ exposes the entire Administrative Objects API, unchanged, via the Formativ applet language. Use this reference to learn about the Administrative Object API, and how you can use it directly within your Formativ applets.

  • Microsoft Scripting Web Site

    • The Microsoft Scripting Web site is the best source for the latest information about Visual Basic Script. You can access more samples, documentation, updates and news about VBS, including product updates and fixes.

  • Microsoft Visual Basic Script Newsgroup

    • The Microsoft hosted Visual Basic Script Newsgroup server lets you ask questions about Visual Basic Script to your peers online. The VBS newsgroup is an excellent source of information for all aspects of programming with Visual Basic Script


Obtaining Technical Support

If you are currently online, select one of the following links to access the appropriate support resource:

Formativ Updates Page

There may be an update that addresses your problem. This page should be your first stop should you encounter a problem.

Formativ Support Page

The Formativ Support page contains links to various support resources.

Advansys Formativ Frequently Asked Questions (FAQ)

Advansys maintains a list of frequently asked questions about Formativ. Check this page to see if the answer to your question has already been documented.

Formativ Support Forums

Advansys provides technical support for Formativ via online moderated forums. These web-based forums are moderated by Advansys technical staff and represent the primary source of support for Formativ. Feel free to log in and post a question or search the existing forums to see if your question has already been answered.


Understanding Formativ Development

Traditional GroupWise Development

Early versions of Novell GroupWise provided a macro based development environment. These macros allowed users and developers alike to build both simple and complex solutions based on the GroupWise system. The macro paradigm was one many people understood, and lent itself well to a broad variety of solutions. Other programming interfaces were also available, but these required a deeper understanding of the development process, and were beyond the capabilities of many people.

The advent of GroupWise 5.x brought about a new development approach for GroupWise. The macro/scripting capabilities of GroupWise 4.x were removed and replaced with several new COM-based programming interfaces, the Object API and the C3PO API. The ability to work at a token level was still available, using either another COM-based interface or the low-level TPH API. The functionality available in macros was still available, but developers now had to use a combination of API's and third and fourth generation languages to access the same functionality.

While GroupWise programmability remained rich, many developers believed it was difficult to develop GroupWise solutions. This was particularly true of developers who had experience developing for other collaboration products, such as Microsoft Outlook. Outlook shipped with an integrated development environment that allowed users to use industry standard Visual Basic to develop solutions. In comparison, for GroupWise, even seemingly simple tasks such as adding a button to a toolbar required a knowledge of COM programming.

GroupWise Development using Formativ

Formativ lets developers create applets for Novell GroupWise using a single, unified development environment. The applets you write or record use a simple, yet powerful language that is 100% compatible with Visual Basic Script language. Visual Basic Script is a powerful, easy to learn programming language, very similar to Visual Basic.

Formativ wraps and exposes the various traditional GroupWise programming APIs with Visual Basic Script. This means that the entire GroupWise Object API, Administrative Objects API and Token Commander APIs are all completely accessible from within the applets you create. In addition, the majority of the Custom Third Party Objects (C3PO) API is accessible via applets. Developers do not require any knowledge of these APIs, or how they interact with each other when using Formativ. They are all presented as simple applet commands and functions.

Developing applications with Formativ is very simple:

Write a new applet

You write a new applet within the Formativ development environment, which is tightly integrated with the GroupWise client. You do not need to own a third party development environment, such as Visual Basic, Delphi or Visual C++. Your applets are written using Formativ's 100% compatible Visual Basic Script language with extensions for GroupWise support. The Formativ environment includes a fully featured applet editor. Depending on configuration, your applet is either saved locally, or to a shared area where it can be accessed by many users.

Integrate the applet with GroupWise

Once you have written and tested an applet, it can be integrated with the GroupWise client. This means that you specify how and when the applet is run. You can choose to add buttons to toolbars that run applets, as well as add items to both standard and context (right-mouse button) menus that activate your applet. You can also associate your applet with many standard GroupWise events, such as on client start-up and on message send. In this way your applet is automatically executed when that particular event is fired.

Distribute the applet

Depending on your installation configuration, you may now distribute your new applet. If you are an administrator, you can simply make your applet and its integrations available to users. When your users next start GroupWise, your applet becomes available to them. If you have associated integrations with an applet, they too become active. For example, your users might see a new button appear on a toolbar that runs an applet. Configured in an appropriate manner, users are not aware they are running applets - the new functionality your applet offers appears to be new functionality in GroupWise.


Designing and Deploying Solutions

What Formativ can do

You can use Formativ to provide an incredibly wide range of GroupWise solutions. Because Formativ makes use of all the major GroupWise programming interfaces, almost anything you might previously have developed using C++, Visual Basic or Delphi can now be developed using simple applets... from within the GroupWise client!

You can use Formativ as a simple tool to automate repetitive tasks. For example, you can write applets to automate such tasks as opening a particular view, proxying to a different user or configuring the GroupWise client a certain way.

You can use Formativ to record applets. You can use the Formativ applet recorder to create new applets. Simply start recording, perform some actions in GroupWise, stop recording, then play back or edit the automatically created applet.

You can use Formativ to add new functionality to the GroupWise client. For example, a 'search and replace' applet ships with the product that adds search and replace capabilities to items that are being composed. When this applet is added to a toolbar or to context menus, it appears to be another integrated GroupWise feature. Formativ ships with many other sample applets in this category, including multiple signatures and template support.

You can use Formativ to automate difficult or critical tasks. For example, a sample 'Vacation Rule' applet ships with the product that guides users through the process of creating a vacation rule that will not create a mail storm.

You can use Formativ to integrate GroupWise with other systems. For example, you could easily write an applet that imports Outlook information into GroupWise, or queries corporate databases to obtain information that is inserted or used by GroupWise. Examples of applets that integrate GroupWise with other systems are included in the standard installation.

You can use Formativ to build complete solutions for GroupWise. Formativ applets are surprisingly powerful, and can be used to build complex business systems. As Formativ applets are COM based, you can use any other COM service from within your applets. This means you can add new functionality to the applet language, and access almost any other modern software services, such as databases, human resource systems, financial systems or sales systems - all from within your applets. The only limit is your imagination!

What Formativ cannot do

While Formativ is an extremely powerful and flexible development environment, like any tool it does have some limitations.

Since Formativ applets use Visual Basic Script, it does not provide visual form design capabilities (although it does provide a comprehensive applet and HTML-based dialog design capability).

Formativ does not currently allow for the creation of new custom message types (although support for such is planned for a future release).

Formativ is unable to add new buttons or toolbar items to the GroupWise address book dialog. This is an architectural restriction imposed by GroupWise.

Designing an applet

Formativ applets are written using a Visual Basic Script compatible programming language. Like any language, you should follow sound design principles when planning and writing your applet. While program design is beyond the scope of this document, presented below are a few points and hints to keep in mind when designing and writing applets with Formativ.

Main processing subroutine

As detailed below, each and every applet must have a subroutine called Main(). This is the subroutine that Formativ executes when an applet is run. If your applet is reasonably complex, you should break it down into manageable blocks of logic, using functions and subroutines to perform specific tasks. Your Main subroutine should clearly document what your script actually does. If your Main() subroutine looks too complex, it probably contains too much code and should be broken into discrete units of functionality as discussed below.

Discrete units of functionality

When designing applets of any complexity, you should always separate logical operations into their own functions or subroutines. If an individual code unit is more than fifty lines long, then it probably should be broken up into two or more smaller functions/subroutines. Dividing your logic into smaller blocks will result in applets that are more reliable, easier to maintain and easier to debug.

We recommend that you adopt a standard for the use of comments within your applets and adhere to it. The judicious use of comments will greatly assist others to understand your applet, and can even be useful when you come back to an applet you wrote after a period of time.

Wizard blocks

In some cases it makes sense to guide users through a particular process using a 'Wizard' approach, where a series of dialogs are displayed in a particular order to guide the user, asking for appropriate input during the sequence. Users are accustomed to this approach, and therefore it makes sense to use this model where appropriate.

The Formativ language extensions make it easy to implement wizard dialogs. For detailed examples of how to implement wizard style dialogs in Formativ, see the 'Address Book Publisher' and 'Vacation Rule' sample scripts.

A simple example of wizard dialog handling is presented below. In each case, the select statement calls a function that will call the Execute function of a dialog. Depending on the button pressed by the user, the variable called Cmd is assigned a particular value. This value is used to determine which dialog is displayed next. The entire processing step is executed inside a Do While loop so that the dialogs are always displayed until the user exits the applet:

Sub Main(ClientState, GWEvent)

     cDoIntro = 101

     cSelectRule = 102

     cDecline = 103

     cSelectDate = 104

     Dim IntroDlg

     Dim RuleDlg

     Dim DeclineDlg

     Set IntroDlg = Utilities.NewROLabelDialog

     Set RuleDlg = Utilities.NewCheckListDialog

     Cmd = cDoIntro

     Do While Cmd is not cExit

           'Present introduction dialog

           if Cmd = cDoIntro then

                 Select Case DoIntro(IntroDlg)

                       Case Btn1      Cmd = cSelectRule

                       Case Btn2      Cmd = cExit

                       Case Btn3      GroupWise.RuleListDlg

                       Cmd = cExit

                 End Select

                 bIntroDlg = TRUE

           End If

           'Select the rule types to be generated

           if Cmd = cSelectRule Then

                 Select Case SelectRule(RuleDlg)

                       Case Btn1      Cmd = cDecline

                       Case Btn2      Cmd = cExit

                       Case Btn3      Cmd = cDoIntro

                       Case Btn4      GroupWise.RuleListDlg

                       Cmd = cExit

                 End Select

           End if

     Loop

End Sub


Applet Structure

Applet Entry Point

Every applet you write must contain a subroutine called Main(). This is the main entry point of every applet, and the subroutine the Formativ environment attempts to execute when an applet is run. You cannot run an applet that does not contain a properly formed Main subroutine.

Your Main() subroutine must pass in two parameters to your applet: Client and GWEvent . It does not matter what these parameters are called, but we recommend you use the Formativ standard of Client and GWEvent. They must be present in every Main() subroutine, or your applet will not execute. The purpose and use of the mandatory parameters are discussed in the following section.

The absolute minimum applet that will run in the Formativ environment is shown below:

Sub Main(Client, GWEvent)

End Sub

Main Parameters: Client and GWEvent

The Main() subroutine in every applet must provide two parameters: Client and GWEvent. These two parameters contain useful context information regarding the state of the GroupWise client when the applet is executed. You can use the values contained in these two arguments to determine the currently selected message or messages in GroupWise, and to modify the behavior of your applet depending on the event (if any) that was fired when your applet was executed.

Client

This parameter represents the state of the GroupWise client at the time your applet was executed. It is the same as the GroupWise C3PO ClientState Object as documented in the GroupWise C3PO documentation. Your applet should not assume a specific Client object is in a particular state. Rather, the ClientName, MajorVersion, and MinorVersion properties should be checked to identify the appropriate state of the object.

Properties

ClientName(R/O) String

CommandMessage (R/O) - Message The Message object associated with the command object being executed. For example, when a predefined command is issued (such as Forward, Open, or Delegate), this property identifies the message associated with the command.

MajorVersion (R/O) String

MinorVersion (R/O) String

SelectedFolder(R/O) Folder. The currently selected folder. For open message items, this property is NULL. For the browser window, this is the folder selected in the folder tree. Calendar windows have the ability to multi-select the folders that are displayed, in which case, this property is the "caret" folder (or focus selection) in the folder tree.

SelectedMessages (R/O) MessageList. The currently selected set of messages.

Methods

RevokeDeliveryFolder( string MessageClass, [Variant Target] )

Reverses the effect of calling SetupDeliveryFolder. Messages of the given class will no longer be linked to the target folder. If multiple servers are monitoring a given message class, this method will remove the delivery folder for all servers. There is no type of "reference count" associated with calls to SetupDeliveryFolder.

MessageClass names a specific message type. Target names the target folder. Target can be a Folder object from the Object API or a string. A string value is interpreted to be a full folder path. For example, \\user_full_name\folder A\Folder B would indicate that Folder B is the target folder. Note that for GroupWise 5.x, this parameter must always be omitted.

SetupDeliveryFolder( string MessageClass, [Variant Target])

Causes messages of the specified class to be automatically linked to the named folder. This is accomplished by creating a rule that causes items of the designated class to be linked to the folder upon delivery of the item.

MessageClass names a specific message type. Target names the target folder. Target can be a Folder object from the Object API or a string. A string value is interpreted to be a full folder path. For example, \\user_full_name\folder A\Folder B would indicate that Folder B is the target folder. Note that for GroupWise 5.x, this parameter must always be omitted.

A C3PO would invoke this method to facilitate the management of messages. For example, processing of delivered items can be accomplished by using this method. The C3POServer would query the folder when the deliver event is passed to the EventMonitor. If more than one C3PO invokes this method with the same parameters, the GWClientState object will attempt to resolve to the same rule. This is done through the naming of the rule.

Each C3POServer should take care to invoke this method only once. The server must keep a one-time init flag (perhaps in the registry) to guarantee that it invokes the method only once. The start-up overhead with this API is substantial and should be avoided.

Example One

In the following code, the ClientState property of the Client argument is used to access the command message from GroupWise. The command message is the currently active, saved message in GroupWise.

Sub Main(Client, GWEvent)

Dim Msg

on error resume next

Set Msg = GroupWise.ComposingItem

if Msg is Nothing then

on error resume next

Set Msg = Client.ClientState.CommandMessage

ComposeMode = FALSE

if Msg is Nothing then

MsgBox("Sorry, the message type could not be identified")

Exit Sub

End If

End If

End Sub

Example Two

In the following code, the ClientState.SelectedMessages property of the Client argument is used to access the list of currently selected items in GroupWise. If there are no items selected, an attempt is made to access the command message.

Sub Main(Context, GWEvent)

Dim Msg

iCount = Context.ClientState.SelectedMessages.Count

if iCount > 0 then

for x = 1 to iCount

Set Msg = Context.ClientState.SelectedMessages.Item(x)

' Do something with the msg object

Set Msg = nothing

Next

Else

Set Msg = Context.ClientState.CommandMessage

' Do something with the msg object

Set Msg = nothing

End If

End Sub

Example Three

In the following code, the ClientState version methods are called to display the major and minor version numbers of the GroupWise client in a message box.

Sub Main(Client, GWEvent)

MsgBox(Client.ClientState.MajorVersion & " " & Client.ClientState.MinorVersion)

End Sub


Understanding the Formativ Object Model

What is the Formativ Object Model?

The Formativ Object model is a collection of objects you can use to access GroupWise from your applets, and to perform other functions that are not built inherently into Visual Basic Script, such as custom dialog support.

The Formativ Object model appears as extensions to the Visual Basic Script language. It is exposed via two main objects: GroupWise and Utilities. Using these two objects is exactly the same as using any other Visual Basic Script objects.

The Formativ Object model is documented in the Formativ Language guide.

The GroupWise Object

The GroupWise object is the key to accessing the GroupWise system. It contains more than three hundred base methods for accessing the GroupWise message store and client. It also exposes many other objects that in turn publish many more objects and methods you can call within your applets.

One of the most important properties of the GroupWise Object is the Account property. The account property returns an object representing the Account object of the native GroupWise Object API. This object gives you complete access to the GroupWise message store. See the Novell Object API documentation for complete details about the use and capabilities of the Object API.

You do not have to be concerned with logging in programmatically when using the GroupWise.Account object. This is handled by Formativ.

To call any of the GroupWise object's methods, simply reference the GroupWise object in your applet, add a period and then the method, including any parameters. For example, to display the GroupWise 'About' Dialog, your applet would look like:

Sub Main(Client, GWEvent)

     GroupWise.AboutDlg

End Sub

Likewise, to access the GroupWise message store via the GroupWise.Account object, simply reference the object and call the appropriate methods, or access the appropriate properties. For example, to display some information about the current GroupWise account, you could write the following applet:

Sub Main(Client, GWEvent)

     MsgBox(GroupWise.Account.Owner.DisplayName)

     MsgBox(GroupWise.Account.TCPIPAddress)

End Sub

When using properties that return an object, you can simplify your code by assigning the returned object to a variable, then using the variable as if it were the original object. For example, the preceding example could also be written as:

Sub Main(Client, GWEvent)

     ' Dimension a variable

     Dim MyAccount

     ' Set it to the GroupWise.Account object

     Set MyAccount = GroupWise.Account

     ' Access the .Account object

     ' using the MyAccount variable

     MsgBox(MyAccount.Owner.DisplayName)

     MsgBox(MyAccount.TCPIPAddress)

End Sub

See the Visual Basic Script documentation for more information.

The Utilities Object

The Utilities Object provides services that are not provided in standard Visual Basic Script, including dynamic dialog creation and other services. Like the GroupWise object, the Utilities object is used in the same way as any other Visual Basic Script object. See the Language Guide for full details.


Recording Applets

The Formativ applet recording facility gives you a head start writing applets by allowing you to record actions within GroupWise, and then convert those actions into applets. You can then run the newly recorded applets as-is, or you can edit and extend them as you please.

NOTE: The applet recording facility is only available in Formativ Administrator and Formativ Developer.

Starting Recording

To start recording, select Formativ | Start Recording from the main GroupWise menu. At this point Formativ is recording GroupWise events. Perform the series of actions in GroupWise you wish to record, then stop the recording process as detailed below.

Stopping Recording

To stop recording, select Formativ | Stop Recording from the main GroupWise menu. Formativ stops recording GroupWise events and automatically displays the applet editor. The applet editor contains a new applet based on the actions you recorded in GroupWise. You can now execute the applet, edit it, rename it, and integrate it with the GroupWise client as desired.

Important

GroupWise does not allow Formativ to record every action you could conceivably perform. For this reason, a recorded applet may not play back exactly the same functions as recorded. In some cases, it may not play back at all. In these situations you will have to manually edit the applet to get it to perform the desired action. See the language guide for information on what commands you should use to achieve your goals.


Working with Automation Objects

Formativ applets are COM based. This means it is very easy to use third party automation objects within your applets. The ability to use third party objects with ease from within your applets opens up huge possibilities for automation and collaboration between GroupWise and third party applications you may use. For example, you might write an applet that accesses sales or product information from a corporate database via its automation object and inserts that information directly into a new GroupWise email message in response to a customer request.

What are Third Party Automation Objects?

Third party automation objects are objects that expose services to other applications or programming tools through automation interfaces. Many commercial Windows applications expose some or all of their services as COM objects. These objects are available to you as a developer. For example, Microsoft Word exposes many of its services via COM, so you are able to access Word programmatically and perform a whole range of document manipulation functions. You could automatically start Word, and build a new letter based on information you provide, such as address and salutation details. Likewise, you can programmatically access the facilities of Microsoft Excel using its exposed COM interfaces. By checking the appropriate application's documentation you can see if it exposes any of its services as COM objects.

See the 'Address Book Publisher' sample applet installed with Formativ for an example of using the COM objects exposed in Microsoft Word. This sample publishes the contents of a GroupWise address book using Word COM objects.

Where are Third Party Automation Objects documented?

Third party objects will be documented by the author of the object, the documentation is normally found in the relevant programmers guide or software development kit (SDK) that ships with the product. You may need to request this information from the vendor directly, although most make this information freely available.

If you use a development tool such as Microsoft Visual Basic or Borland Delphi, you can often import or open an object's Type Library and see the various methods and properties you can call on an object.

Using Third Party Automation Objects in an applet

Before you can use an automation object in an applet, you need to create an instance of it. You create an instance of an automation object using the CreateObject method. Search for CreateObject in the Visual Basic Scripting help documentation from Microsoft for full details.

To create an automation object, assign the object returned by CreateObject to an object variable:

Dim objWord

Set objWord = CreateObject("Word.Application")

This code starts the application that creates the object (in this case, Microsoft Word). Once an object is created, refer to it in code using the object variable you defined. As shown in the following example, you can access properties and methods of the new object using the object variable, objWord, and other Word objects, including the Selection object and the Word.Documents collection:

' Manipulate Word

Set S = objWord.Selection

'Replace Tags with variable text

S.HomeKey wdStory

Set DocRange = Word.Documents(TemplateName).Content

'Address Book Name

Call DocRange.Find.Execute("ABName", FALSE, TRUE, FALSE, , , TRUE, FALSE, FALSE, ABook, wdReplaceAll)

'Address Book Name

S.HomeKey wdStory

Call DocRange.Find.Execute("COMPANY NAME", FALSE, TRUE, FALSE, , , TRUE, FALSE, FALSE, sCompName, wdReplaceAll)

S.EndKey

Set objWord = nothing

The last line of this sample sets the object variable objWord to nothing. This has the effect of releasing the Word object. It is very important that you release any objects you create once you are finished with them.

In some cases an instance of an automation object may already be active on a computer. In this situation it would be wasteful to create another instance of the object. You can check in your applet for the existence of an object prior to creating a new instance yourself. For example:

Function CheckWord(ByRef Word)

     CheckWord = TRUE

     ' Resume with the next line following the error.

     On Error Resume Next

     ' Attempt to reference Word, which is already running.

     Set Word = GetObject(, "Word.Application")

     If Word Is Nothing Then ' If true, Word is not running.

           ' Create a new instance of the Word application.

           Set Word = CreateObject("Word.Application")

           If Word Is Nothing Then ' If true, MS Word 8.0 is not installed.

                 MsgBox "MS Word is not installed on your computer."

                 CheckWord = FALSE

           End If

     End If

End Function

This code first checks to see if a Microsoft Word object is already available to use. If an instance cannot be found, a new instance is created. Note the use of the On Error Resume Next construct to trap the error that would occur if the GetObject function fails.

Creating your own Automation Objects to use in applets

In some cases you may be unable to achieve a certain result using applets alone. For example, you may wish to display a complex dialog to a user when building a new email message that cannot be built using the supplied dialog creation functions. Another example might be a time consuming operation that takes too long to perform using an applet. Both these requirements can be met by creating your own automation object, and calling its methods from your applet.

Creating a new automation object is beyond the scope of this document. However, there are many excellent resources available to developers that guide you through the process. The best of these are the user and programmer guides that ship with the development tools used to create automation objects. The simplest way to create a new automation object is with a fourth generation tool such as Borland's Delphi or Microsoft's Visual Basic . Both these development environments provide tools to make creating new automation objects easy.


Accessing GroupWise Information

Formativ gives you full access to the GroupWise message store. Using applets, you are able to locate existing items (email messages, appointments, tasks, notes, address book entries and documents), create new items, delete and modify existing items.

Formativ also lets you access items that are still being composed and do not yet exist in the message store. For example, you can access an email message that is still being composed and modify any of its data, such as the body text or subject. In this way you can write an applet that automatically inserts a standard disclaimer every time you create a new message, or inserts a particular signature into the message.

The following sections detail how to create new items, how to access items that are still being composed, and how to access items that already exist in the message store. Since accessing GroupWise address book/contact information is slightly different from the generic message types, it is described in its own topics, 'Accessing Address Book Information via the Account' and 'Accessing Address Book Information via the AddressBooks Object'.


The Message Store

The GroupWise message store is a proprietary database that usually resides on a network server. A GroupWise Post Office contains a message store. From a Formativ perspective, there is only one message store from which all messages can be accessed.

All items (other than address book data) accessible using Formativ are known as messages. A message represents a discrete item in the GroupWise message store.

All messages share some identical features, such as a unique ID, which is used to uniquely identify an item in the message store. Distinctive message types, such as email messages and appointments, have unique properties that set them apart from the other types. For example, an appointment will have a start time, whereas an email will not.

Messages in the message store are based on a hierarchical structure. Every item is of type "GW.MESSAGE". Each distinctive type of message is further delimited by type. For example, an email message is of type "GW.MESSAGE.MAIL". An appointment type is "GW.MESSAGE.APPOINTMENT". A complete list of the base types is shown below:

GW.MESSAGE - The base message type

GW.MESSAGE.MAIL - Email message

GW.MESSAGE.APPOINTMENT - Appointment

GW.MESSAGE.TASK - Task

GW.MESSAGE.NOTE - Note

GW.MESSAGE.DOCUMENT - Document

Third parties are free to extend this list of messages by creating a new message type based on one of the above types. For example, you might come across a message in the message store of type "GW.MESSAGE.MAIL.PROJECTX", which indicates a new type of email message.

A message is represented by an object . An object is a variable that has a set of properties that can be used to get and set information about the object, and methods that can be used to perform operations on that object. For example, all message objects have a property called MessageID that can be used to determine the unique ID for that message, and a method called Delete that deletes the item from the message store.

Identifying items in GroupWise

As mentioned in the previous section, every message in the GroupWise message store has a unique ID. This is a string that is guaranteed to be remain unique for the life of the message in the message store.

Accessing the Message Store

The GroupWise message store is accessed using the Account property of the GroupWise object in an applet:

Dim objAccount

Set objAccount = GroupWise.Account

objAccount now holds an instance of the GroupWise account object. The entire GroupWise message store can now be accessed via the account object.

The Account object is exactly the same as the Account object that is returned when using the standard GroupWise Object API. This is a very important point. The GroupWise Object API Account object, and all the methods and objects it supports, are documented on Novell's web site. Any Object API code you may have previously written can now be used essentially unchanged within an applet.

The following sections discuss how to use the Account object to create new items in the message store, how to access items already in the message store and how to access an item that is being composed and is not yet in the message store.


Accessing item in the message store

Accessing items in the message store

Accessing pre-existing items

In many cases you might need to access GroupWise items programmatically. For example, you may need to extract all appointments for a given day, or access the currently selected messages. There are a number of different techniques available to you, depending on what you need to achieve.

Accessing items directly from the message store

GroupWise items already in the message store are accessed in two main ways. If you know the message ID of the item you are interested in, you can access the message directly. If you are simply interested in all messages of a particular type, you can use various message extraction techniques to query for the messages you are interested in.

In either case you use methods of the GroupWise.Account property. The GroupWise.Account property gives you full access to the GroupWise message store. See Novell's Object API documentation for complete details of the objects and methods available.

If you already have the message ID of a particular message, you can easily extract it from the message store using the GroupWise.Account.MailBox.Messages object. For example, the following applet attempts to access a message using its ID and display the subject of the item in a message box:

Sub Main(Client, GWEvent)

' Hard coded message ID

Const MSG_ID = "35FE9AD8.GWHQ.MOSMAN.100.1636E61.1.4A.1"

Dim objMessages

Dim objMsg

' Set a variable to the MailBox.Messages object

Set objMessages = GroupWise.Account.MailBox.Messages

' Get the message using its ID and set it to objMsg

Set objMsg = objMessages.Item(MSG_ID)

' Display the message subject text

MsgBox(objMsg.Subject)

' Release the objects

Set objMsg = nothing

Set objMessages = nothing

End Sub

In other situations you may wish to extract any number of messages from GroupWise and process them. For example, you may wish to process all tasks from your account. Use the methods of the GroupWise.Account object to access the appropriate messages.

For example, you might wish to process all the tasks in your account . To extract each task, we can use the GroupWise.Account.Calendar.Messages collection. In the following applet, the subject of each task is displayed.

Sub Main(Client, GWEvent)

Dim objMessages

Dim objTasks

Dim objTask

' Set a variable to the Calendar object

Set objMessages = GroupWise.Account.Calendar

' Use a filter to locate personal, accepted tasks

Set objTasks = objMessages.FindMessages("(TASK) AND (ACCEPTED) AND (BOX_TYPE = INCOMING OR BOX_TYPE = PERSONAL)")

' Display the subject and message ID of each task located

for each objTask in objTasks

MsgBox(objTask.Subject & " - " & objTask.MessageID)

next

' Release the objects

Set objTasks = nothing

Set objTask = nothing

Set objMessages = nothing

End Sub


Creating a New Item

There are two main techniques you can use to create a new item. The first technique creates a new message in the message store with no user interface. The second creates a new item in the GroupWise client.

No user interface

You can create any message type without any user interface. You would normally use this approach when you have all the information required to create a new item, and there is no need for user interaction. For example, you might write an applet that reads a database containing email addresses then creates and sends a customized email message to each person in the list. In this case there is no need for a user to see the actual messages being composed.

Although there are several variations, the most common way to create a new message is to call the Add method of the messages collection owned by the folder in which you wish to store the message. For example, the following applet creates a new personal GroupWise appointment in your own calendar:

Sub Main(Client, GWEvent)

     Dim objMessage

     ' Create the new message

     Set objMessage = GroupWise.Account.Calendar.Messages.Add("GW.MESSAGE.APPOINTMENT", 3)

     ' Set some properties

     objMessage.OnCalendar = TRUE

     objMessage.FromText = GroupWise.Account.Owner.DisplayName

     objMessage.Subject = "This was created using Formativ"

     ' Display the message ID of the new message

     MsgBox(objMessage.MessageID)

End Sub

The Calendar and Messages objects, and the Add method are all documented in the GroupWise Object API documentation, which is freely available from Novell's web site. (Remember that the Account property of the GroupWise object gives you complete access to the entire GroupWise Object API.)

In another example, we create a new personal task in your own calendar:

Sub Main(Client, GWEvent)

     Dim objTask

     ' Create the new task

     Set objTask = GroupWise.Account.Calendar.Messages.Add("GW.MESSAGE.TASK", 3)

     ' Set some properties

     objTask.OnCalendar = TRUE

     objTask.FromText = GroupWise.Account.Owner.DisplayName

     objTask.TaskCategory = "A"

     objTask.TaskPriority = 1

     objTask.Subject = "This was created using Formativ"

     ' Display the message ID

     MsgBox(objTask.MessageID)

End Sub

Finally, a slightly more complex example, creating a new email message to oneself. Again, the only user interface element used is the message box at the end of the process which displays the unique message ID of the email. All the objects and properties used in this example are documented in the GroupWise Object API documentation.

Sub Main(Client, GWEvent)

     Dim objDraft

     Dim objEmail

     Dim objRecipient

     ' Create a draft email message

     Set objDraft = GroupWise.Account.MailBox.Messages.Add(4)

     ' Add a single recipient - ourself

     objRecipient = objDraft.Recipients.Add(objDraft.Sender.EmailAddress,,0)

     ' Add some properties

     objDraft.Subject = "This was created using Formativ"

     objDraft.BodyText.PlainText = "This is the body text of the email message"

     ' Send the email by calling the send method

     Set objEmail = objDraft.Send

     ' Display the message ID

     MsgBox(objEmail.MessageID)

End Sub

If you have the Formativ development environment open in GroupWise when a new message arrives, you might notice a slight delay in notification of the message's arrival. We recommend that you close the Formativ development environment whenever you are not editing applets.

Obviously, you may use all Visual Basic Script constructs in your code. For example, here is the same example slightly modified to send the same message to our mailbox three times. The subject of each message is modified each time a new message is sent:

Sub Main(Client, GWEvent)

     Dim objDraft

     Dim objEmail

     Dim objRecipient

     ' Create three new messages

     for x = 1 to 3

           ' Create a draft email message

           Set objDraft = GroupWise.Account.MailBox.Messages.Add(4)

           ' Add a single recipient - ourself

           objRecipient = objDraft.Recipients.Add(objDraft.Sender.EmailAddress,,0)

           ' Add some properties

           objDraft.Subject = "This is message no. " & x

           objDraft.BodyText.PlainText = "This is the body text of the email message"

           ' Send the email by calling the send method

           Set objEmail = objDraft.Send

     next

     MsgBox("Done!")

End Sub


Creating a New Item (User Interface)

Sometimes you may wish to create a new message in the GroupWise client itself. Using Formativ applets, you can create a new message by displaying the new message dialog for the type of message you wish to create. You can then leave it to the user to complete the rest of the details, or you can optionally fill out some or all of the details before making the item available to the user.

For example, in the following code we create a new email message, and leave it to the user to complete and send the message manually. When the applet is executed, the standard GroupWise new email message dialog is displayed:

Sub Main(Client, GWEvent)

     GroupWise.NewMail

End Sub

In some cases you may wish to fill out some of the message properties before making the item available to the user. For example, you may wish to complete the subject and body text, as shown in the following example, using the ComposingItem property of the GroupWise object. Notice this example uses an error check to ensure that a valid composing item is accessible:

Sub Main(Client, GWEvent)

     Dim Msg

     ' Create a new visible email message

     GroupWise.NewMail

     ' Attempt to access the composing item

     ' If available, set its subject and body text

     Set Msg = GroupWise.ComposingItem

     if Msg is Nothing then

           MsgBox("No composing item available")

     else

           Msg.Subject = "This is the new subject"

           Msg.BodyText = "This is the body text"

           Set Msg = nothing

     end if

End Sub

Refer to the Language Guide for full details of the ComposingItem property. The property is also covered in more detail in the following section.

Formativ is only able to access the ComposingItem if the dialog displaying the new message has the focus at the time you access it. This is a limitation of the underlying GroupWise architecture, rather than Formativ and is not usually an issue as long as you attempt to access the item soon after it is created.


Accessing Items via the client

Accessing items selected in the GroupWise client

In many cases, you may wish to write an applet which operates on the currently selected GroupWise items. For example, you might wish to perform some operation on a list of selected items in GroupWise, or you might wish to access the currently opened saved item, such as an email message that arrived in your mailbox.

In order to determine which, if any, messages are selected in the GroupWise client when your script is run, you should use the Client parameter passed into the Main procedure of your applet. The Client parameter is an object which represents the state of the client when your applet was executed. See the earlier section entitled Applet Structure for full details on the definition of the Client parameter.

If you wish to act upon all selected messages in the GroupWise client, you should check the Client.ClientState.SelectedMessages object. If any messages are selected, you can then use this object to access each one. For example, the following code displays the subject of each selected item in GroupWise. Before running the applet, display a list of items in the GroupWise client and select them:

Sub Main(Client, GWEvent)

     Dim objMsg

     ' Find out how many items are selected in GroupWise

     iCount = Client.ClientState.SelectedMessages.Count

     ' If any are selected, access each one

     if iCount > 0 then

           for x = 1 to iCount

                 ' Get the message and display its subject

                 Set objMsg = Client.ClientState.SelectedMessages.Item(x)

                 MsgBox(objMsg.Subject)

                 Set objMsg = nothing

           Next

     else

           MsgBox("No messages were selected")

     end if

End Sub

If you wish to act upon a single, saved item, either simply selected or opened , you can use the Client.ClientState.CommandMessage object. The CommandMessage object gives you access to the current saved GroupWise item. For example, the following applet checks if the CommandMessage object is not empty. If a command message is active, its subject is displayed.

Sub Main(Client, GWEvent)

     Dim objMsg

     On Error Resume Next

     Set objMsg = Client.ClientState.CommandMessage

     if not objMsg is Nothing then

           MsgBox(objMsg.Subject)

           Set objMsg = nothing

     end if

End Sub

You can use the two preceding techniques together to process either single or multiple items. For example, you may have an applet that processes either a single, opened item, or multiple selected items. You can check the state of the client and process the items in the following manner:

Sub Main(Client, GWEvent)

     Dim objMsg

     On Error Resume Next

     iCount = Client.ClientState.SelectedMessages.Count

     if iCount > 0 then

           for x = 1 to iCount

                 Set objMsg = Client.ClientState.SelectedMessages.Item(x)

                 MsgBox(objMsg.Subject)

                 Set objMsg = nothing

           next

     else

           Set objMsg = Client.ClientState.CommandMessage

           if not objMsg is Nothing then

                 MsgBox(objMsg.Subject)

                 Set objMsg = nothing

           end if

     end If

End Sub

The previous example is a very flexible technique, and one that is used consistently in many applets that need to process either a single or selected scripts. A good design choice would be to write a function that takes the message object as a parameter, and is called for each SelectedMessage instance or for a single CommandMessage instance.


Accessing the item being composed

In some situations you may wish to access data in a new GroupWise message that is still being composed. An item is still being composed when it has not been sent or committed. For example, when you create a new email message, the message is not saved until you press the send button. Likewise, when you reply to an existing email message, your reply is not saved until you press the send button.

The distinction between a saved and an unsaved message is very important from a programmer's perspective. Until a GroupWise message has been saved, it does not have a unique message identifier, and it does not exist in the message store. This means you cannot use any of the GroupWise.Account methods to access the message. The only way you can read and write an item that has not yet been saved is to:

Use the ComposingItem property of the GroupWise Object

or

Use the ItemSetText and ItemGetText methods of the GroupWise Object, using the special "X00" message ID to identify the message.

Every message in the GroupWise message store is allocated a unique ID that never changes during the life of the message. Items that have not been saved, and therefore have not yet been allocated a permanent message ID, can be accessed using the special message ID "X00". This ID can usually be used in place of a permanent ID in methods and properties, to access the current composing item. The only caveat is that the item being composed needs to have the Windows focus for this technique to work.

The ComposingItem property of the GroupWise object provides a convenient method to access items that are currently being composed. The ComposingItem property lets you read and write data in items being composed, including Subject and body text. The ComposingItem property exposes the following properties:

BoxType: Integer (Read Only)

ClassName: String (Read Only)

ConvertAttachments: Boolean

CreationDate: Date (Read Only)

Deleted: Boolean (Read Only)

FromText: String

Hidden: Boolean

MessageID: String (Read Only)

NotifyWhenDeleted: Integer

NotifyWhenOpened: Integer

Opened: Boolean

Parent: Variant (Read Only)

Priority: Integer

Read: Boolean

ReplyDaysRequested: Integer

ReplyRequested: Integer

Routed: Boolean

RoutingEndOfLine: Boolean (Read Only)

Sender: String (Read Only)

ViewName: String

IsPrivate: Boolean

Subject: String

BodyText: String

CC: String

BC: String

To_: String

StartDate: Date

EndDate: Date

DueDate: Date

CallerCompany: String

CallerName: String

CameToSee: Boolean

PleaseCall: Boolean

ReturnedCall: Boolean

Telephoned: Boolean

Urgent: Boolean

WantsToSee: Boolean

WillCall: Boolean

AssignedDate: Date

TaskCategory: String

TaskPriority: String

In the following example, the ComposingItem property is used to insert a simple disclaimer at the top of the body text of a message being composed. To be useful, this applet would be associated with the On Send event for email messages so that it would be automatically executed each time a new email message is sent:

Sub Main(Client, GWEvent)

     ' This is the disclaimer text to insert

     Const DISCLAIMER = "This is some disclaimer text"

     Dim NewLine

     Dim Msg

     NewLine = Chr(13) & Chr(10)

     ' Attempt to access the composing item

     Set Msg = GroupWise.ComposingItem

     ' If we have the composing item, insert the disclaimer into the body text

     if not Msg is Nothing then

           Msg.BodyText = DISCLAIMER & NewLine & NewLine & Msg.BodyText

           Set Msg = nothing

     else

           MsgBox("No GroupWise items were available for disclaimer insertion.")

     end if

End Sub


Accessing Address Book Information via the Account

Formativ gives you complete access to the GroupWise address books. With Formativ, you can write applets to create new address books, add, edit and delete address book entries, and quickly extract contact details.

There are two main techniques you can use to access address book information. You may use the standard GroupWise.Account object, which provides lower-level, yet more difficult to use access, or the GroupWise.AddressBooks object, which provides slightly higher-level, yet simpler access. The technique you use will ultimately depend on the problem you are trying to solve.

Address book entries in GroupWise do not have accessible persistent ID's as do other item types such as email items. This means you cannot save an address book item's ID, then access it directly at a later time. This is due to architectural issues in GroupWise. You can add your own custom field to address book entries, and assign it a unique value, such as a GUID, and then use the GUID value as a unique ID during later sessions.

Using the GroupWise.Account Object

The GroupWise.Account object provides low level access to address book data. You can access data down to the FieldDef level, and work with custom fields. Access via the GroupWise.Account object is the same as the Object API. See Novell's Object API documentation for complete details.

For example, the following code displays the name of every address book available in the current account:

Sub Main(Client, GWEvent)

     Dim objAddressBooks

     Dim objAddressBook

     ' Get the address books object

     Set objAddressBooks = GroupWise.Account.AddressBooks

     ' Display the name of each address book

     for each objAddressBook in objAddressBooks

           MsgBox(objAddressBook.name)

     next

     Set objAddressBooks = nothing

End Sub

You may access an individual address book by name or by its index value within an address books collection. For example, the following applet lists the email address for each contact in an address book called 'Frequent Contacts':

Sub Main(Client, GWEvent)

     Dim objAddressBooks

     Dim objAddessBook

     Dim objAddressBookEntry

     ' Get the address books object

     Set objAddressBooks = GroupWise.Account.AddressBooks

     ' Locate the address book called "Frequent Contacts"

     Set objAddressBook = objAddressBooks.Item("Frequent Contacts")

     ' Display the email address of each entry in the book

     for each objAddressBookEntry in objAddressBook.AddressBookEntries

           MsgBox(objAddressBookEntry.EmailAddress)

     next

     Set objAddressBooks = nothing

End Sub

Essentially, this technique uses 'raw' GroupWise Object API calls. Our experience has been that the GroupWise Object API can be a little unstable when accessing certain address books, particularly the Novell LDAP address book. Using the GroupWise.AddressBooks object removes this instability since Formativ shields you from the instability.


Accessing Address Book Information via the Address Books Objects

Accessing Address Book Information via the AddressBooks Object

The GroupWise.AddressBooks object provides a clean, simple object model with which you can access GroupWise address books. This technique shields you from much of the instability inherent in some of the native GroupWise address book calls. More importantly, it encapsulates the GroupWise address book FieldDef paradigm, making it very simple to access address book fields by name without having to worry about Field Definitions or the version and language of the GroupWise client being used.

See the Object Model documentation for full details of the GroupWise.AddressBooks object model.

Semantically, using the GroupWise.AddressBooks object is similar to using the GroupWise.Account model. For example, the applet to list the names of all the address books available in an account is:

Sub Main(Client, GWEvent)

     Dim objAddressBooks

     Dim objAddressBook

     Set objAddressBooks = GroupWise.AddressBooks

     for Each objAddressBook in objAddressBooks

           MsgBox(objAddressBook.Name)

     Next

     Set objAddressBooks = nothing

End Sub>

Likewise, the code to access a single address book by name is:

Sub Main(Client, GWEvent)

     Dim objAddressBooks

     Dim objAddressBook

     Set objAddressBooks = GroupWise.AddressBooks

     ' Locate the address book called "Frequent Contacts"

     Set objAddressBook = objAddressBooks.Item("Frequent Contacts")

     ' Display the email address of each entry in the book

     for each objAddressBookEntry in objAddressBook

           MsgBox(objAddressBookEntry.EmailAddress)

     next

     Set objAddressBooks = nothing

End Sub

Note that you do not have to use the .AddressBookEntries object as you do when using the GroupWise.Account access technique.

The real benefit to using the GroupWise.AddressBooks object becomes apparent when you have to access address book entry fields. Unlike the GroupWise.Account technique, you can access all standard fields directly using properties of the AddressBookEntry object. There is no need to be concerned with FieldDefs, the version or language of the GroupWise client being used as is the case when accessing most fields using the GroupWise.Account technique.

GroupWise's underlying architecture dictates that address book fields traditionally had be accessed using field names. These textual field names varied between versions of the client being used and the language of the client being used. For example, if you wanted to write a program that accessed the 'Title' field of an address book, it was necessary to know the local variation of that name. If the user had an English client, the field called 'Title' was located. If the user had a French client, your program had to be aware of this and search for '*' instead.

Formativ alleviates this problem through its implementation of the GroupWise.AddressBooks object. For example, if you wanted to extract the 'Title' field contents of every contact in a particular address book, you could do so by using the Title property of the AddressBookEntry object as shown here:

Sub Main(Client, GWEvent)

     Dim objAddressBooks

     Dim objAddressBook

     Set objAddressBooks = GroupWise.AddressBooks

     ' Locate the address book called "Frequent Contacts"

     Set objAddressBook = objAddressBooks.Item("Frequent Contacts")

     ' Display the email address of each entry in the book

     for each objAddressBookEntry in objAddressBook

           MsgBox(objAddressBookEntry.Title)

     next

     Set objAddressBooks = nothing

End Sub

This technique also makes adding new address book entries very simple. For example, to add a new contact to a personal address book called "Test Book", you could use the following applet:

Sub Main(Client, GWEvent)

     Dim AddressBooks

     Dim AddressBook

     Dim oAddressBookEntries

     Dim oAddressBookEntry

     Set AddressBooks = GroupWise.AddressBooks

     On Error Resume Next

     Set AddressBook = AddressBooks.Item("Test Book")

     if IsEmpty(AddressBook) then

           MsgBox("Could not locate that address book")

     else

           MsgBox(AddressBook.Name)

           Set oAddressBookEntry = AddressBook.AddContact("Bill Smith")

           with oAddressBookEntry

                 .FirstName = "Bill"

                 .LastName = "Smith"

                 .Organization = "Smith Inc"

                 .EmailAddress = "bill@Smith.com"

                 .EmailType = "NGW"

                 .Address = "This is the address"

                 .City = "The city"

                 .State = "The state"

                 .ZipCode = "The zip"

                 .Country = "The country"

                 .Department = "The dept"

                 .Title = "The title"

                 .MailStop = "The mailstop"

                 .Greeting = "The greeting"

                 .OfficePhone = "1111111"

                 .HomePhone = "22222"

                 .CellPhone = "333333"

                 .FaxPhone = "444444"

                 .Comments = "This is the comments field"

           end with

     end if

     Set AddressBooks = nothing

     MsgBox("Done")

End Sub

Note:

This technique still affords you the opportunity of accessing the native GroupWise Object API interfaces for address books via the AddressBookEntry.Objects and AddressBook.Objects properties.


Controlling the Client

Formativ provides many methods within the GroupWise object to manipulate the GroupWise client user interface. These range from displaying dialogs to opening and closing the various views. Check the Formativ Language Guide for full details.

For example, to display the GroupWise About dialog, simply call the GroupWise.AboutDialog method:

Sub Main(Client, GWEvent)

     GroupWise.AboutDlg

End Sub

Note: Take care not to close GroupWise down programmatically using an applet since closing GroupWise while an applet is executing may cause unpredictable results, and may even result in an access violation. You should always check if a window is open before using one of the window closing/cancelling commands.


Creating Dialogs and Forms

Creating user interfaces with applets

Because Formativ applets are written using Visual Basic Script, you cannot design forms and dialogs in the same way you can using a language like Visual Basic. Visual Basic Script is a procedural language that provides little in the way of user interface design elements.

Formativ provides a number of extensions to the VBS language to allow you to design simple, yet flexible dialogs in your applets. You can build dialogs that display information, collect information from the user (using forms), or both.

You can also build dialogs using HTML. See here for more information.

With a little practice, you can built quite complex forms. All of the dialogs and forms you see when executing the samples that ship with Formativ were built using the Formativ dialog extensions in applets.

Simple user interaction

There are two main commands you can use to provide feedback to your users and request input, InputBox and MsgBox.

The following applet prompts the user to enter some text, a new GroupWise message is created and the subject of the new message is set to the value input by the user:

Sub Main(Client, GWEvent)

Dim Msg

' Get a subject from the user

sSubject = InputBox("Enter the subject for the new message", "Formativ Example")

' Create a new email message in the user interface

GroupWise.NewMail

' Find the new message and set up its subject

Set Msg = GroupWise.ComposingItem

if Msg is Nothing then

MsgBox("No composing item available")

else

Msg.Subject = sSubject

Set Msg = nothing

end if

End Sub

Advanced Users

Please see the Formativ Language Guide for information about using the Utilities object to build custom dialogs in your applets. Also, refer to the sample applets installed with the product for examples of custom dialogs built using the Utilities Object model.


Formativ Portal Manager

The Formativ Portal Manager is a powerful new feature that lets you create and embed portals into the GroupWise client. A portal is a window that can display many different types of data. The types of data you can display depends on the software you have installed on your computer, but at a minimum you can display web sites, XML, HTML and images. The Formativ Portal Manager lets you create and display any number of portals directly in the GroupWise client. You can also programmatically access the information being displayed in a portal.

The Portal Manager requires Novell GroupWise 6.01 or greater. Novell have also released a beta FTF file for the GroupWise 5.5.7.1 Enhancement Pack client which enables the use of the Formativ Portal Manager™ based solutions with the GroupWise 5.5 EP client. See Novell TID 2963458 for details on the update and information on how to download the GroupWise 5.5.7.2 Beta FTF file (f32eppp1.exe).

To learn more, click on one of the following topics:

What is a portal?

Creating a portal

Displaying a portal

The portal user interface

Creating portal content

The FormVariables object

Getting information out of a portal

Opening GroupWise Items from a portal

Executing applets from a portal

Portal Object Model


What is a Portal?

A Portal is a custom window that appears embedded in the GroupWise client. It can be used to display any information that Microsoft Internet Explorer can display, such as HTML, XML, images, web sites, etc.

You can display pre-existing content in a portal (such as a web site or XML file), or you can display content built dynamically by a Formativ applet. For example, you could write an applet that extracts all of today's appointments from your GroupWise calendar, builds HTML representing the appointments, then display the HTML file in the portal.

Formativ ships with a Today View applet that creates a portal containing information about today's appointments and tasks. This is how the GroupWise client appears when executed:

Portal Characteristics

Portals are custom windows that appear in the GroupWise client

Portals appear in the message/calendar list area of the GroupWise client

Portals use Microsoft Internet Explorer to display content (you need to have Microsoft Internet Explorer 5.5 or greater installed to use the portal manager)

You can build dynamic content and display it in a portal, or display existing content, such as a web page or intranet

You can extract information from a portal and use it an applet

You can use a portal to open GroupWise items by clicking on specially formatted HTML links

You can customize the appearance of a portal window to include standard browser buttons, captions, etc

Portals are persistent. This means that a portal and its contents remain active during a GroupWise session, even if hidden. This means you can display live content in a portal (such as a web site), hide the portal then open it again later in the same session and have its content unchanged.

Portals use Microsoft's Internet Explorer security settings. This means the settings defined in IE's Internet Options will also affect any portals you create.

You can create any number of portals. If more than one portal exists and they are visible, each portal appears on its own tab within the GroupWise client. Users can click a tab to activate a portal, or an applet can programmatically activate a particular portal


Creating a Portal

Portals are created and managed using the Formativ Portal Manager. The Formativ Portal Manager is accessed via the Formativ Portal Object model. Click here to learn about the Portal Object model.

The Portal Manager

The Formativ Portal Manager is accessed via the GroupWise.PortalManager object. For example, the following code sets the variable iPortals to the portal manager's Portals collection.

' Get an instance of the Portals collection
Set iPortals = GroupWise.PortalManager.Portals

To create a new portal, simply call the .Add method of the PortalManager.Portals object. The .Add method returns a new portal object. The following code creates a new portal object and sets some properties. Note that this does not display the portal in the client.

Set iPortal1 = iPortals.add
iPortal1.Caption = "Advansys Home"
iPortal1.TabCaption = "Advansys"
iPortal1.ID = "PORTAL1"
iPortal1.NavigationControlsEnabled = TRUE
iPortal1.URLInputEnabled = TRUE
iPortal1.Url = PORTAL_URL1

Portal IDs

Each portal has a unique ID which is accessible via the .ID property of the Portal object. A portal ID is a string that uniquely identifies a portal. Portal ID's are used to locate portals within the portal collection. You can manually allocate a portal ID (as is done in the example above), or you can let Formativ automatically allocate IDs for you. The Portal Manager will allocate an ID of "Portal1" to the first portal you create, "Portal2" to the second and so on. It is often useful to override the default portal ID with something more meaningful so that you can programmatically access the portal later in the session. (Remember that portals are persistent within a GroupWise session. Even after an applet that created a portal has finished running, the portal will persist until the user explicitly destroys the portal, the portal is destroyed by an applet, or GroupWise is shutdown.)

Checking if a Portal Exists

There are many instances where your applets need to check if a particular portal already exists. For example, you may have an applet that creates a portal to display a particular web site. You want your users to be able to keep the portal active for the current GroupWise session, even if the portal is hidden during the session. Each time the applet is executed, it should first check to see if the portal has been previously created. If it has, the portal simply needs to be displayed. If it has not been previously created, it needs to be created then displayed.

This functionality can be achieved by checking for the portal via the Portals.Item property:

Set iPortal1 = iPortals.Item("PORTAL1")

' If the above code did not return a portal, create it (this will happen the
' first time the applet is executed during a session).
if iPortal1 is nothing then
Set iPortal1 = iPortals.add
iPortal1.Caption = "Advansys Home"
iPortal1.TabCaption = "Advansys"
iPortal1.ID = "PORTAL1"
iPortal1.NavigationControlsEnabled = TRUE
iPortal1.URLInputEnabled = TRUE
iPortal1.Url = PORTAL_URL1
end if

In this example, we try to set iPortal1 to be the portal with the unique ID "PORTAL1" by passing the portal ID to the portals.Item property. If a portal with this ID exists, it is assigned to the iPortal1 variable, and can then be shown. We check for an object by comparing the return variable (iPortal1) against the nothing data type:

if iPortal1 is nothing then

...


Displaying a Portal

To display a portal, call its .Show method. This has the effect of displaying all portals that have their visible property set to TRUE.

Portals are displayed in the message/calendar list area of the GroupWise client. If messages were being displayed when the portal was shown, you need to hide the portal in order to see the messages again. You can still view calendar data by selecting a calendar view in GroupWise. Reselecting a message view in the client causes the portal(s) to reappear. The opposite effect is seen if the user has a calendar view open when a portal is shown.

IMPORTANT: Portals are asynchronous in nature. This means that when a portal is shown, your applet continues to run. This means you cannot pause your applet and wait for certain conditions to be met before continuing. You can achieve the same result by using the portal applet execution feature.

To Display a Portal

To display a portal, call its .Show method. For example

iPortal1.Show

To Select a Portal

If more than one portal exists, each portal is shown on a single tab. Calling a portals .Show method is not sufficient in order to have that portal be the one that is ultimately shown if more than one portal exists. To ensure a particular portal is visible, you need to set the Portals.ActivePortal property. The ActivePortal property is a string representing the unique ID of the portal that is currently visible. For example:

iPortals.ActivePortal = "PORTAL1"

Makes the portal with the ID "PORTAL1" the frontmost portal in the GroupWise client.


The Portal User Interface

Portals appear within the GroupWise client. They appear in the message list/calendar area of the client. The portal interface consists of a toolbar, the portal itself, and a number of tabs if more than one portal has been defined. The user can select which portal to view by clicking on the tabs, or you can programmatically define which portal should have the focus.

An example of the portal interface is shown below. In this example, four portals have been defined, as indicated by the four tabs at the bottom of the portal area. Also visible is the portal toolbar, which provides navigation control:

You can customize the controls that appear on individual portal toolbars by using the properties exposed by the portal object. For example, you can make a URL edit control appear on one portal but not another.

Customizing the portal toolbar

You customize the portal toolbar for an individual portal by using the properties exposed by the Portal object. The appropriate properties are:

.Caption = [string value]

The .Caption property specifies the text that appears at the top of the portal page within the toolbar area. This property is optional, and an empty value results in no caption being displayed.

.TabCaption = [string value]

The .TabCaption property specifies the text that appears on the tab holding this portal. The tab is only visible if more than one portal has been created.

.NavigationControlsEnabled = TRUE|FALSE

The .NavigationControlsEnabled property specifies whether the HTML navigation buttons (back, forward, refresh and stop) appear on the portal toolbar.

.URLInputEnabled = TRUE|FALSE

The .URLInputEnabled property specifies whether the URL edit control appears on the toolbar.

.CanClose = TRUE|FALSE

Setting .CanClose to FALSE will hide the Close Portal button and prevent the user from manually closing the Portal. A value of TRUE will display the Close Portal button.

.HideCloseControlsEnabled = TRUE|FALSE

Setting .HideCloseControlsEnabled to TRUE hides the Hide all Portals, Hide this Portal and Close this Portal buttons. A value of TRUE will display all close and hide buttons, unless the CanClose property is FALSE, in which case the Close this Portal button will not be displayed.


Creating Portal Content

There are two main ways to get content into a portal for display: Use existing data (such as a web site or local HTML), or have your applet dynamically create content and load it into a portal for display.

Using Existing Data

The primary means of loading existing data into a portal is to use the portal.URL property. The .URL property is a string that accepts any properly formed URL. A URL can be the address of a web site, or the full path to a file. (Assuming you have an appropriate browser plugin installed, you can view documents other than HTML directly in the portal.)

For example, to browse to the Advansys web site, use the following syntax (assuming iPortal represents a Portal object):

iPortal1.Url = "www.advansyscorp.com"

To load the contents of a file into a portal, use:

iPortal1.Url = "C:\FileList.txt"

Creating Content

Portal objects expose a .HTML property. This string property lets you both read and write the HTML contents of a portal. (Of course, you may only read HTML content if the portal is displaying HTML.)

Writing a value to the .HTML property clears the portal of any existing data and loads it with the given HTML content. The HTML string supplied must represent a valid HTML document.

This technique makes it possible to dynamically build content based on GroupWise data, or any other accessible data. For example, you could write an applet that extracts calendar information from your GroupWise account, then builds a HTML representation of the data. This HTML is finally loaded into a portal and displayed.

For example, here is a simple applet that builds dynamic HTML content and displays it to the user in a portal:

Dim iPortal1
Dim iPortals

Set iPortals = GroupWise.PortalManager.Portals
Set iPortal1 = iPortals.Item("Example")

if iPortal1 is nothing then
Set iPortal1 = iPortals.add
iPortal1.ID = "Example"
iPortal1.NavigationControlsEnabled = TRUE
iPortal1.HTML = "<html><body>Hello " & GroupWise.Account.Owner.DisplayName & ", welcome to Formativ!</body></html>"
end if

iPortal1.Show
iPortals.ActivePortal = iPortal1.ID


The FormVariables Object

The FormVariables object is used to access values from a HTML form. The FormVariables object is a collection of FormVariable objects. A FormVariable object represents the name and value of a HTML form element. The FormVariables object is updated whenever a POST operation is performed within a portal that contains a HTML form.

The FormVariables Object

The FormVariables object is available for use automatically within an applet. It does not have to be instantiated from any other objects. The FormVariables object is a collection of FormVariable objects (see below), and exposes the following properties and methods:

FormVariables.Count

FormVariables.Count is a read-only integer property. It returns the number of FormVariable objects currently in the collection.

FormVariables.Item(Index integer)

FormVariables.Item is a read-only property. It returns the FormVariable object that has the given index value.

FormVariables.ItemByName(Name string)

FormVariables.ItemByName is a method. It returns the FormVariable object that has the name given in Name. The .ItemByName method is a convenient means to determine if a FormVariable with a given name exists in the collection.

The FormVariable Object

The FormVariable object represents a single HTML form variable. All FormVariable objects are managed by the FormVariables object. FormVariable exposes the following properties:

FormVariable.Name

FormVariable.Name is a read-only string property. It contains the name of the HTML form variable.

FormVariable.Value

FormVariable.Value is a read-only string property. It contains the value of the HTML form variable.

Mapping HTML to FormVariable Objects

Formativ automatically maps HTML form elements to FormVariable objects when the POST operation is called on a form:

<FORM METHOD="POST">

<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0">

<TR VALIGN="MIDDLE">

<TD VALIGN="MIDDLE" ALIGN="LEFT" CLASS="headingdate"></TD>

<TD VALIGN="MIDDLE" ALIGN="LEFT" WIDTH="50%" COLSPAN="2">[TODAY_DATE]</TD>

<TD VALIGN="MIDDLE" ALIGN="RIGHT" WIDTH="50%" COLSPAN="2" HEIGHT="35">

<INPUT TYPE="HIDDEN" NAME="formativapplet" VALUE="today view_flexlock.vbf"><INPUT TYPE="SUBMIT" NAME="DisplaySettings" VALUE="Settings..."></TD>

</TR>

</TABLE>

</FORM>


Getting Information out of a Portal

Not only do Formativ portals let you define content, they also expose the contents of a portal to your applets. This powerful feature gives you the power to:

Extract and process the raw HTML a portal may be displaying

Extract data from HTML forms being displayed in a portal

Execute a Formativ applet from a portal

Extracting HTML from a portal

The portal object exposes a property called .HTML. The .HTML property is a read/write string property that lets you access the raw HTML code currently being displayed in a portal. This feature lets you create applets that can visit a web site and analyze its content.

To access a portal's raw HTML, simply read the .HTML property into a string variable. For example, the following applet creates a portal, navigates to a web site and counts the number of bold on attributes ("<B>") found:

const BOLDATTR = "<B>"
Dim iPortal1
Dim iPortals
Dim iHTML

Set iPortals = GroupWise.PortalManager.Portals
Set iPortal1 = iPortals.Item("Example")

if iPortal1 is nothing then
Set iPortal1 = iPortals.add
iPortal1.ID = "Example"
iPortal1.NavigationControlsEnabled = TRUE
iPortal1.URL = "www.advansyscorp.com"
end if

iPortal1.Show

' Wait for the portal to load
while ((iPortal1.ReadyState <> READYSTATE_COMPLETE) and
(iPortal1.ReadyState <> READYSTATE_INTERACTIVE))
Utilities.DoEvents
wend

iHTML = iPortal1.HTML

iFound = 0
iPos = 0
iPos = InStr(1, iHTML, BOLDATTR, vbTextCompare)
while iPos > 0
iFound = iFound + 1
iPos = InStr(iPos + Len(BOLDATTR), iHTML, BOLDATTR, vbTextCompare)
wend

MsgBox iFound & " instances of <B> were found."

It is important to note that the portal.HTML property will not return the portal's source code until the entire document has been loaded. You can check this by querying the Portal.ReadyState property, documented in the Language Guide. A peculiarity of the Microsoft Internet Explorer window used by the portals is that it does not return the appropriate ready state unless it is visible. This means that you need to display a portal via its .Show method to ensure it has completely loaded before you can reliably query the .ReadyState and .HTML properties.

Extracting Data from HTML Forms

It is easy to extract data from portals displaying HTML forms. The ability to extract data from a portal, coupled with the ability to execute an applet from a portal (see below), makes it easy to build very powerful and flexible data collection systems in GroupWise. For example, you could create a portal that displays a HTML form to the user. When the user completes the form and presses a button on the form, the data entered on the form can then be used by another applet to perform further processing. For example, see the Today View applet that ships with Formativ.

The FormVariables object is used to access data from a HTML form. This object lets you access the names and values of every named HTML form element contained in a portal.

For example, the following applet creates a portal that displays a simple HTML form. The form consists of two text edit controls and a button. When the button is pressed, the applet is automatically re-executed via a portal trigger. The applet determines that it has been executed as a result of a portal trigger, then uses the FormVariables object to access and display the values of the two text edit controls.

dim iDlg

'-------------------------------------------------------------------------------
' Main line processing
'-------------------------------------------------------------------------------
Sub Main(Client, GWEvent)

ExecutePortal

' If the Ok button pressed
If (GWEvent = "HTML_TRIGGER") then
ReadUserData
end if

End Sub

'-------------------------------------------------------------------------------
' Execute the portal
'-------------------------------------------------------------------------------
Sub ExecutePortal

Dim iPortal
Dim iPortals

iPortalID = "Test"

Set iPortals = GroupWise.PortalManager.Portals
Set iPortal = iPortals.Item(iPortalID)

if iPortal is nothing then
Set iPortal = iPortals.add
with iPortal
.Caption = "Formativ Business Solutions"
.TabCaption = "Test"
.ID = iPortalID
.OpenMessages = TRUE
.RunApplets = TRUE
.HTML = Utilities.LoadStringFromFile(Utilities.GetDataDirectory + "testPortal.htm")
end with
end if

iPortal.Show
iPortals.ActivePortal = iPortalID

End Sub

'-------------------------------------------------------------------------------
' Read the dialog value if 'Ok' button pressed
'-------------------------------------------------------------------------------
Function ReadUserData

dim iProcess
dim iNameCTL
dim iAddressCTL

' If the OK button pressed
Set iProcess = FormVariables.ItemByName("MROK")
if not iProcess is nothing then
' Get the text inside the name field
Set iNameCTL = FormVariables.ItemByName("nameCTL")
if not iNameCTL is nothing then
call msgbox(iNameCTL.value, vbInformation, "Name")
end if

' Get the text inside the address field
Set iAddressCTL = FormVariables.ItemByName("addressCTL")
if not iAddressCTL is nothing then
call msgbox(iAddressCTL.value, vbInformation, "Address")
end if
end if

set iProcess = nothing

End Function

The HTML used by this example is shown below. Note the hidden input element named "formativapplet". This is a specially coded <INPUT> type that tells Formativ it needs to execute the applet named in the VALUE element when the button is pressed. Notice also that the two edit box controls have been named 'nameCTL' and 'addressCTL'. These names map directly to the FormVariables object in Formativ, and are used to name the instances of the FormVariable objects returned by the FormVariables collection. You can see these objects being accessed in the applet example above.

For example, to obtain the value of the text entered in the INPUT control called 'nameCTL', we could use the following applet code:

Set iNameCTL = FormVariables.ItemByName("nameCTL")
if not iNameCTL is nothing then
call msgbox(iNameCTL.value, vbInformation, "Name")
end if

<HTML>

<HEAD>

<TITLE></TITLE>

</HEAD>

<BODY>

<FORM METHOD="POST">

<TABLE WIDTH="100%">

<TR>

<TD></TD>

<TD HEIGHT="50">Enter text and click 'Ok'.</TD>

</TR>

<TR>

<TD>Name: </TD>

<TD> <INPUT TYPE="TEXT" NAME="nameCTL" SIZE="60"></TD>

</TR>

<TR>

<TD>Address:</TD>

<TD> <INPUT TYPE="TEXT" NAME="addressCTL" SIZE="60"></TD>

</TR>

<TR>

<TD></TD>

<TD></TD>

</TR>

<TR>

<TD></TD>

<TD ALIGN="RIGHT"><INPUT TYPE="HIDDEN" NAME="formativapplet"

VALUE="Test.vbf"><INPUT TYPE="SUBMIT" NAME="MROK" VALUE="Ok">&nbsp;&nbsp;</TD>

</TR>

</TABLE></FORM> </BODY>

</HTML>


Opening GroupWise items from a Portal

Formativ portals recognize specially formatted links within HTML as links to messages in the GroupWise message store. Using this technique, you can dynamically build HTML that lets users click on a link that automatically opens any GroupWise message. For example, the Today View applet that ships with Formativ dynamically builds HTML representing calendar information. When any item in the portal is clicked by the user, the original GroupWise message represented by that item is automatically opened.

Creating a Portal that supports automatic opening of GroupWise messages

In order for this feature to work, you need to set the Portal.OpenMessages property to TRUE. Portal.OpenMessages is a read-write boolean property. Portal.OpenMessages is FALSE by default.

For example, the following code snippet shows how to create a portal that supports automatic opening of GroupWise messages:

Set iPortal1 = iPortals.add
iPortal1.OpenMessages = TRUE

Encoding GroupWise message IDs

In order to build HTML that automatically opens a GroupWise message, you need to build a specially formatted HREF element containing the message ID of the message to be opened (a message ID is a unique message identifier). A properly formed message ID HREF element is shown below:

<A HREF="UID:[Message ID]">[Description]</A>

Where:

[Message ID] is the unique message ID of the message to be displayed when the link is pressed, and

[Description] is the text that describes the link.

An example of such a link is:

<A HREF="UID:3C8467EB.GWDEVDOM.GWDEVPO.100.16D676D.1.68B.1"><B>Sales Meeting</B></A>

This HTML code will result in a link being displayed with the label Sales Meeting. When the link is clicked, the original GroupWise message (in this case an appointment) will be automatically opened for the user.

For example, the following applet extracts the subjects of the currently selected messages from your GroupWise account and displays each subject in a portal. When a subject entry is clicked, the original GroupWise item is opened:

Sub Main(Client, GWEvent)

Dim iHRT
Dim iMsg
Dim iPortal
Dim iPortals
Dim iHTML

iHRT = Chr(13) & Chr(10)

Set iPortals = GroupWise.PortalManager.Portals
Set iPortal = iPortals.Item("Example")

if iPortal is nothing then
Set iPortal = iPortals.add
iPortal.ID = "Example"
iPortal.OpenMessages = TRUE
iPortal.NavigationControlsEnabled = FALSE
end if

iCount = Client.ClientState.SelectedMessages.Count
for x = 1 to iCount
Set iMsg = Client.ClientState.SelectedMessages.Item(x)
iHTML = iHTML & iHRT & "<A HREF=""UID:"& iMsg.MessageID &"""><B>" & iMsg.Subject & "</B></A><BR>"
next

iPortal.HTML = "<HTML><BODY>" & iHTML & "</BODY></HTML>"
iPortal.Show
iPortals.ActivePortal = iPortal.ID

End Sub


Executing Applets from a Portal

Formativ portals let you optionally execute an applet when a portal HTML button is pressed. This is useful for when you need to perform further processing based on the content of a portal. For example, the Today View applet has a settings button. When this button is pressed, another HTML page is loaded into the same portal that allows users to specify user interface settings. When the OK button on this portal is pressed, the settings entered are used to redisplay the Today View portal. All this functionality is achieved by automatically executing the same applet from within the portal and using data obtained via the FormVariables object.

Executing an Applet from a Portal

You can execute a Formativ applet by defining a hidden HTML <INPUT> element within a HTML form. When a SUBMIT action is sent (as a result of pressing a button, for example), Formativ looks for any hidden <INPUT> elements that are formatted to execute applets. If it finds one, Formativ executes the applet defined in the tag.

A properly formatted <INPUT> element is shown below:

<INPUT TYPE="HIDDEN" NAME="formativapplet" VALUE="[appletname]">

Where:

[appletname] is the name of the applet to execute, including the .VBF extension.

For example, the following HTML code snippet defines a HTML form that contains a SUBMIT button with the caption "Settings...". When this button is pressed, Formativ locates the <INPUT TYPE="HIDDEN" NAME="formativapplet" VALUE="today view_flexalock.vbf"> tag and executes the applet called "today view_flexalock.vbf".

<FORM METHOD="POST">

<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0">

<TR VALIGN="MIDDLE">

<TD VALIGN="MIDDLE" ALIGN="LEFT" CLASS="headingdate"></TD>

<TD VALIGN="MIDDLE" ALIGN="LEFT" WIDTH="50%">Date</TD>

<TD VALIGN="MIDDLE" ALIGN="RIGHT" WIDTH="50%>

<INPUT TYPE="HIDDEN" NAME="formativapplet" VALUE="today view_flexalock.vbf"><INPUT

TYPE="SUBMIT" NAME="DisplaySettings" VALUE="Settings..."></TD>

</TR>

</TABLE>

</FORM>

IMPORTANT: This technique can only be used to execute local applets.

Determining if an applet is being executed via a portal

In many cases your applet needs to know if it is being executed as a result of a portal input tag as described above. For example, the above code causes the today view_flexalock.vbf applet to be executed. This is the same applet that dynamically built the original portal. When this applet is executed as a result of the "Settings..." buttons being pressed, instead of redisplaying the Today View portal, we need it to display the Settings portal content instead.

An applet can detect if it is being executed as a result of a portal by checking the GWEvent argument that is passed into every applet. If the GWEvent argument equals the string "HTML_TRIGGER", the applet is being executed as a result of a portal trigger.

For example, the following code snippet illustrates how it is possible for an applet to perform different processing if it was executed as a result of a portal trigger:

Sub Main(Client, GWEvent)

if GWEvent = "HTML_TRIGGER" then
DetermineAction
else
DisplayView
end if

End Sub

In this example, the applet will call the DetermineAction subroutine if the applet is being called as a result of a portal trigger. Otherwise, the applet will call the DisplayView subroutine.

If the DetermineAction subroutine was called, it would probably use the FormVariables collection to access the data that was entered into the form at run time.


Portal Object Model

GroupWise.PortalManager

Returns the single instance object of the PortalManager.

PortalManager

There is only one instance of the PortalManager available at any time. The PortalManager persists for the duration of the GroupWise session.

PortalManager.Portals

Returns a reference to the single Portals object.

PortalManager.ShowAll

Shows all portals

PortalManager.HideAll

Hides all portals

Portals

Portals is a collection of individual Portal objects. It is returned by the PortalManager.Portals property.

Portals.Count

Returns the number of Portals which have been created.

Portals.Item

Returns the Portal object identified by the Index parameter. The index parameter can be an integer or a string portal ID.

Portals.Delete

Deletes and destroys the Portal identified by the Index parameter. The index parameter can be an integer or a string portal ID.

Portals.Clear

Clears and destroys all Portals.

Portals.Add

Creates and returns a new Portal. A unique Portal ID is assigned automatically. The string ID can be set to another value by using the Portal.ID parameter. See the Portal object for details.

Portals.ActivePortal

Sets or returns the active Portal ID by using the Portal.ID parameter string value.

Portal

A Portal represents a single portal object. A portal will persist for the duration of a GroupWise session unless it is explicitly destroyed by the user or by an applet.

Portal.ID

The unique string ID associated with a Portal. A portal ID is automatically assigned when you create a new portal, or you can define your own.

Portal.Caption

Sets or returns the text located at the top left of the Portal toolbar.

Portal.TabCaption

Sets or returns the Portal tab caption text.

Portal.TabVisible

Sets or returns whether the Portal tab is visible or hidden.

Portal.HTML

Sets or returns the HTML source for each Portal. Setting the HTML property will render the page within the Portal. Reading the HTML property will return the HTML source displayed in the Portal.

Portal.CanClose

Setting CanClose to FALSE will hide the Close Portal button and prevent the user from manually closing the Portal. A value of TRUE will display the Close Portal button.

Portal.RunApplets

A value of TRUE instructs Formativ to parse and run an applet which is encoded into a HTML form SUBMIT function. This feature enables applets to be executed from an HTML page. A value of FALSE will cause Formativ to process the SUBMIT function as a normal HTML form process and will ignore any embedded applet references.

Portal.OpenMessages

A value of TRUE will instruct Formativ to parse the user selected URL and extract any embedded GroupWise Message ID. If a valid Message ID is found, Formativ will automatically open the associated message and display it using the standard GroupWise client view. A value of FALSE will activate user selected URLs using standard browser operation and will not look for embedded GroupWise Message IDs.

Portal.URL

Setting the URL property will cause the Portal to display the URL. Reading the URL property will return the current URL displayed in the Portal.

Portal.Visible

Setting this property to TRUE will make the Portal visible. Setting the value to FALSE will hide the Portal. Reading the property will return the current visibility of the Portal. See also the Show and Hide methods.

Portal.Delete

The Delete method destroys the Portal and removes the Portal ID from the list of available Portals.

Portal.Show

The Show method makes the Portal visible and sets it as the topmost, active Portal.

Portal.Hide

The Hide method hides the Portal from view.

Portal.URLInputEnabled

Set to TRUE to display the URL navigation edit control. A value of FALSE will hide the URL navigation edit control.

Portal.NavigationControlsEnabled

TRUE displays the Forward, Back, Refresh and Stop Activity browser controls. FALSE hides these browser navigation controls.

Portal.HideCloseControlsEnabled

FALSE hides the Hide all Portals, Hide this Portal and Close this Portal buttons. A value of TRUE will display all close and hide buttons, unless the CanClose property is FALSE, in which case the Close this Portal button will not be displayed.

Portal.ReadyState

Indicates the state of the Web browser component. Read ReadyState to obtain state information specific to the Web browser control. Use this information to avoid attempting to use the Web browser control when it is not ready to perform an action. The portal must be visible in order to obtain an accurate result from this property. The following table lists the possible values:

READYSTATE_UNINITIALIZED | Default initialization state. The Control has not begun loading any properties.
READYSTATE_LOADING | The control is loading its properties.
READYSTATE_LOADED | The control has initialized its properties but is not yet interactive.
READYSTATE_INTERACTIVE | The control is interactive, but not all of its data is available. (It is downloading a document or frame).
READYSTATE_COMPLETE | The control is interactive and all of its data is available. (The current document is fully downloaded.)

Portal.Document

Provides access to the Automation interface of the portal's HTML document. Use Document to access an IDispatch interface for manipulating the contents of the HTML document through the COM object model. If there is no active document, Document is empty. That is, you must first load a document using the HTML or URL properties before you can manipulate it using the Document interface. For more information about the Document interface, see the document object section of Microsoft’s Dynamic HTML reference.


HTML Dialogs

Formativ HTML Dialogs are a powerful new feature that lets you create dialogs using industry standard HTML. A HTML dialog can be used to display information to end users, as well as collecting data from users that can then be used by your applets.

To learn more, click on one of the following topics:

What are HTML dialogs?

Creating HTML dialogs

Displaying HTML dialogs

The standard HTML dialog user interface

Creating content

Getting information out of HTML dialogs

HTML Dialog Object Model


What are HTML Dialogs?

HTML Dialogs represent a new and exciting way to build user interfaces to your Formativ applets. HTML dialogs are modal dialogs whose content consists purely of HTML and related content, such as Javascript. HTML dialogs make it possible to build dialogs that contain interactive content.

An example HTML dialog is shown below:

HTML Dialog Characteristics

HTML Dialogs are modal. This means the dialog must be closed before the applet that created it (and GroupWise) can continue executing.

HTML Dialogs can be displayed as standard floating windows, or they can be embedded into the GroupWise client. A floating dialog can be moved around the screen just like a normal window. Floating dialogs can also be resized. An embedded HTML dialog is displayed in the message/calendar list area of the GroupWise client. Embedded dialogs give the appearance that they are tightly integrated with the GroupWise client.

HTML Dialogs display standard HTML content. They can also contain other Internet content, such as Javascript.

HTML Dialogs can be made to behave in an interactive manner through the use of Java, Javascript, etc.

Data entered into HTML dialogs is accessible from within the Formativ applet that created and displayed it via the FormVariables object.

It is the developer's responsibility to add buttons that close the dialog. However, standard OK and Cancel toolbar buttons can be made to appear on the dialog.


Creating HTML Dialogs

HTML dialogs are created using the Utilities.NewHTMLDialog method. This method returns an instance of a new HTMLDialog object.

Utilities.NewHTMLDialog

The Utilities.NewHTMLDialog method returns an instance a new HTMLDialog object. Once an instance of a HTMLDialog has been instantiated, you setup its properties, and finally call its .Execute method to display the dialog. For example:

Dim aDlg

Set aDlg = Utilities.NewHTMLDialog
aDlg.WindowState = fbsEmbedded
aDlg.Caption = "Publish Address Books to MS Word"
aDlg.HTMLCode = <supply HTML code here>
aDlg.Execute

This code snippet defines a new HTMLDialog, sets its style to fbsEmbedded so that it will appear to be embedded into the GroupWise client, sets its caption and illustrates where the raw HTML containing the dialog controls would be assigned. Finally, the .Execute method is called to display the dialog modally to the user.

You can assign any valid HTML code to the .HTMLCode property. More information about HTML content can be found here .


HTML Dialog Content

HTML Dialogs can contain any valid HTML code. They can also contain HTML related content, such as Java and Javascript in order to add functionality.

HTML Dialog Content

Most HTML dialog content will consist of a HTML <FORM> element with a number of form elements, such as text edit areas, list boxes and combo boxes. The <FORM> will also have at least one <INPUT TYPE="SUBMIT"> element representing a button used to dismiss the dialog. Formativ uses specially formatted <INPUT TYPE="SUBMIT"> elements in order to determine which button the user pressed to dismiss the dialog. More information can be found here.

For example, to create a very simple HTML dialog that displayed a message and an OK button, the following HTML could be used:

<HTML>

<BODY>

<FORM METHOD="POST" NAME="DlgForm">

<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0">

<TR>

<TD VALIGN="MIDDLE">HTML Dialog Test</TD>

</TR>

</TABLE><P></P>

<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0">

<TR>

<TD WIDTH="10"></TD>

<TD></TD>

<TD WIDTH="10" VALIGN="TOP" ALIGN="RIGHT"></TD>

<TD WIDTH="10" VALIGN="TOP" ALIGN="RIGHT"></TD>

<TD WIDTH="75%" VALIGN="TOP" ALIGN="RIGHT"><INPUT TYPE="SUBMIT"

NAME="MROK" VALUE="OK">&nbsp;&nbsp;<INPUT TYPE="SUBMIT"

NAME="MRCANCEL" VALUE="Cancel">&nbsp;</TD>

</TR>

</TABLE></FORM> </BODY>

</HTML>

The important things to note about this HTML are:

Most of the code is within a <FORM> element. This is required in order to use form elements, such as edit controls, list boxes and buttons.

The <FORM> element has its METHOD attribute set to POST. This is required in order for the act of pressing the buttons to be recognized by Formativ.

The two buttons have been defined as <INPUT TYPE="SUBMIT"> controls. This is required in order for the act of pressing the buttons to be recognized by Formativ.

The two buttons have special names assigned to their NAME attributes ("MROK" and "MRCANCEL"). These special names are used by Formativ to specify how the dialog was dismissed. See Adding Buttons to HTML Dialogs for detailed information.

When creating HTML dialog content, you can

Load an existing, external HTML file into a HTML dialog

Dynamically build HTML content within your applet and assign it to the HTML dialog

Load an existing, external HTML file into memory, modify its contents, then assign it to the HTML dialog

Displaying Existing Data in a HTML Dialog

In some instances you may wish to keep the HTML content you are going to use to define your HTML content as separate, external files. This approach is particularly useful when you wish to maintain a central copy of the HTML, or the HTML is going to change on a regular basis.

In order to load an external HTML file into a HTML dialog, the simplest approach is to use the Utilities.LoadStringFromFile method to load the HTML file directly into the HTMLCode property of the HTMLDialog object. For example, the following code snippet creates a new dialog and uses the contents of the file HTML Dialog.htm (located in the Formativ Data Directory) as the contents of the dialog:

Dim aDlg
Set aDlg = Utilities.NewHTMLDialog
aDlg.Caption = "Example HTML Dialog"
aDlg.HTMLCode = Utilities.LoadStringFromFile(Utilities.GetDataDirectory & "HTML Dialog.htm")
aDlg.Execute

Displaying Dynamically Built Data in a HTML Dialog

In many instances you will need to modify the HTML you wish to use prior to displaying a HTML dialog. For example, you may wish to dynamically add items to list box controls, or change text in the dialog, dependent on some external factor. In some instances you may have your applet create dynamic Javascript that populates controls in the dialog, based on the state of some GroupWise data you have just extracted.

The simplest way to create dynamic content is to build markers into your base HTML, load the HTML into a Formativ applet string variable, then manipulate the string in memory to make the appropriate changes. Once the changes are complete, assign the new HTML string variable to the .HTMLCode property and call the .Execute method to display the dialog.

Interactive HTML Dialog Content

Because HTML Dialogs use industry standard HTML and associated technologies, it is easy to build interactive, dynamic dialogs. You can use Java applets, ActiveX controls and Javascript to enrich the functionality of a HTML dialog. For example, using Javascript, you can easily dynamically present different options to users when the user selected a new entry from a combo box.

Details on how to use Javascript (and other tools) to provide dynamic HTML content are beyond the scope of this document. There are many excellent resources available that document in great detail how to achieve a rich user experience.


Adding Buttons to HTML Dialogs

It is the developer's responsibility to provide users with buttons within HTML dialogs that allow for the dismissing of the dialog. Formativ can provide two toolbar buttons that act as OK and Cancel buttons, but this facility does not allow for data to be extracted from the dialogs. These buttons are provided only as an emergency exit for users to dismiss HTML dialogs.

Adding Buttons to HTML Dialogs

Buttons are added to HTML dialogs using HTML <INPUT> elements. An example of a properly formed <INPUT> element is:

<INPUT TYPE="SUBMIT" NAME="[ID]" VALUE="[CAPTION]">

where:

[ID] is a specially coded button identification string (see below), and

[CAPTION] is the string to appear on the button.

As with all HTML form controls, this code must appear within a <FORM></FORM> pair.

For example, a button that acts as an OK button when pressed might be defined as:

<INPUT TYPE="SUBMIT" NAME="MROK" VALUE="OK">

Button Identification

When a user presses a HTML dialog button, Formativ looks to see if it contains a specially coded NAME attribute. Specially coded NAME attributes indicate to Formativ that the dialog should be dismissed, and an appropriate return value handed back to your applet indicating which button the user pressed.

For example, to define a button that dismisses the dialog and indicates to the applet that the OK button was pressed, the following HTML code snippet might be used:

<INPUT TYPE="SUBMIT" NAME="MROK" VALUE="OK">

Note that the NAME attribute has been assigned the string value "MROK". "MROK" is recognized by Formativ as a button that is to dismiss the dialog and indicate to the calling applet that the OK button was pressed.

Valid values for the NAME attribute are:

MROK

MRCANCEL

MRABORT

MRRETRY

MRIGNORE

MRYES

MRNO

Any other values assigned to the NAME attribute are ignored by Formativ. Pressing buttons without one of the above NAME values will not dismiss the dialog. Of course, such a button may initiate some other valid action, such as executing Javascript in the dialog.

When a button containing one of the above NAME attributes is pressed, the dialog is dismissed and control returns to the calling applet. A value indicating which button dismissed the dialog is returned by the HTMLDialog.Execute method. More information is available here.


HTML Dialog User Interface

The Formativ HTML Dialog facility provides only the most rudimentary user interface by default. It is the responsibility of the developer to use HTML elements to provide the appropriate user interface elements, including buttons to dismiss the dialog. Formativ does provide a number of properties that can be used to customize the overall appearance and behavior of your HTML dialogs.

WindowState

The HTMLDialog.WindowState property is a read-write property that lets you control the overall appearance of your dialog. It can take one of three values:

fbsDesigned - The dialog is displayed in the center of the screen.

fbsMaximized - The dialog is displayed maximized.

fbsEmbedded - The dialog is embedded in the GroupWise client.

Width and Height

The HTMLDialog.Width and HTMLDialog.Height properties control the overall width and height of a dialog in pixels. These settings only have an effect if the WindowState property is set to fbsDesigned.

BorderStyle

The HTMLDialog.BorderStyle property is a read-write property that lets you control the type of border your dialog has. It can take one of four values:

fbsNone - The dialog has no visible border.

fbsSingle - The dialog has a single line border.

fbsSizeable - The dialog has a border that allows resizing of the dialog.

fbsDialog - The dialog has a standard dialog border with no control buttons visible.

The BorderStyle property has no effect if the WindowState property is set to fbsEmbedded.

Caption

The HTMLDialog.Caption property is a write-only string property that sets the caption text of the dialog. It has no effect if the WindowState property is set to fbsEmbedded.

ContextMenuEnabled

The HTMLDialog.ContextMenuEnabled property is a write-only boolean property that controls whether the Internet Explorer right-mouse click content menu is enabled when displaying HTML dialogs.

ToolbarVisible

The HTMLDialog.ToolbarVisible property is a read-write property that controls the visibility of the dialog toolbar. The dialog toolbar contains an OK and Cancel button. These buttons return OK and CANCEL values from the HTMLDialog.Execute method. These buttons do not activate the variable extraction routines normally available when using HTML <INPUT> elements to close the dialog.


Displaying HTML Dialogs

HTML dialogs are displayed by calling the HTMLDialog.Execute method. The .Execute method displays the dialog modally, which means the user must dismiss them in order for processing to continue. An applet pauses at the .Execute method until a return value is obtained indicating which button was used to dismiss the dialog.

The Execute Method

The .Execute method returns an integer value indicating which button was used to dismiss the dialog. The possible return values are:

1 - MROK

2 - MRCANCEL

3 - MRABORT

4 - MRRETRY

5 - MRIGNORE

6 - MRYES

7 - MRNO

The labels MROK, MRCANCEL map directly to the names given to the button controls within your HTML. See Adding Buttons to HTML Dialogs for full details.


Getting Data out of HTML Dialogs

Like Formativ Portals, you are able to extract the values of HTML form controls from your HTML dialogs. You access dialog data via the HTMLDialog.Variables property.

The HTMLDialog.Variables property

The HTMLDialog.Variables property is a read-only property that returns a FormVariables object. The FormVariables object is a collection of FormVariable objects. A FormVariable object represents a single HTML element and its value.

Once a dialog has been displayed via its .Execute method, query its Variables property to determine the value of the HTML form elements in the dialog. The FormVariables object is documented here.


HTML Dialog Object Model

Utilities.NewHTMLDialog

Returns an instance of a new HTMLDialog object.

HTMLDialog

You may create any number of HTMLDialog objects in an applet.

HTMLDialog.Execute

Causes the dialog to be displayed modally. Returns an integer value indicating which button dismissed the dialog.

HTMLDialog.OpenGroupWiseMsgs

Specifies whether GroupWise message IDs embedded in HTML will cause the message to be opened when clicked. More information can be found here.

HTMLDialog.Navigate

Loads the HTML code at the given URL.

HTMLDialog.HTMLCode

Read-write string property. Lets you specify the HTML code to be displayed.

HTMLDialog.WindowState

Read-write property. Specifies how the dialog is to be displayed. Possible values are:

fbsDesigned - The dialog is displayed in the center of the screen.

fbsMaximized - The dialog is displayed maximized.

fbsEmbedded - The dialog is embedded in the GroupWise client.

HTMLDialog.Width

Read-write integer property. Specifies a width for the dialog in pixels. Only applicable if WindowState is fbsDesigned.

HTMLDialog.Height

Read-write integer property. Specifies a height for the dialog in pixels. Only applicable if WindowState is fbsDesigned.

HTMLDialog.BorderStyle

Read-write property. Specifies the border style of the dialog. Possible values are:

fbsNone - The dialog has no visible border.

fbsSingle - The dialog has a single line border.

fbsSizeable - The dialog has a border that allows resizing of the dialog.

fbsDialog - The dialog has a standard dialog border with no control buttons visible.

The BorderStyle property has no effect if the WindowState property is set to fbsEmbedded.

HTMLDialog.Variables

Read only property. Returns any variables and their values set by HTML form controls in the dialog. Variables are returned in a FormVariables collection.

HTMLDialog.Caption

Write-only string property. Specifies the caption displayed on the dialog.

HTMLDialog.ContextMenuEnabled

Write-only boolean property. Specifies whether the right mouse menu context menu should be accessible via the dialog.

HTMLDialog.ToolBarVisible

Read-write boolean property. Specifies whether the dialog toolbar, containing OK and Cancel buttons, is visible.


Integrating applets with the Client

One of the most powerful aspects of Formativ is the ease with which you can add buttons to toolbars, items to menus and hook into the GroupWise event system. Traditionally, this has been one of the most difficult aspects of GroupWise development. Formativ lets you add these elements by simply indicating which GroupWise Context you wish to link to these elements.

A GroupWise Context essentially maps to either a message type or to some aspect of the GroupWise client. For example, each message type (email, appointments, notes etc) has its own context. A context is represented by a descriptive name, such as 'GroupWise Email' or 'GroupWise Appointments'. Each context is divided into categories, such as 'Toolbars', 'Menus' and 'Events' and each category is further divided into options. For example, the 'events' category of the 'GroupWise Email' context consists of all the events you can assign scripts to, such as 'On Send' and 'On Open'.

You can see all the contexts and context categories you can use on the integrations tab for each script you have written.

When you assign integrations to an applet, the information about that integration is saved with the applet itself. This means that if you distribute the applet to other users, its integrations will also automatically appear within the GroupWise client. For example, if you write an applet that proxies to some other user, and you decide to create a button on the main GroupWise toolbar that executes the applet, any user you distribute the applet to will automatically have the same button appear on their toolbar the next time they start GroupWise.

At startup, Formativ has to register its interest with any GroupWise context it wishes to integrate into. The underlying GroupWise architecture means that, in some cases, Formativ is unable to register interest in a particular context in time for it to take effect. For example, if you write an applet, and create a button for the applet on the main toolbar, the button will not appear until you restart the client. Formativ will attempt to identify these situations and advise the user that a client restart is required. If any new integrations you design do not appear, or the events you subscribe to do not fire, you should restart the GroupWise client and try again.

Before defining any client integrations, you should define the applet description, help hint and image. Select the appropriate applet in FormativCentral, then activate the properties tab. The properties tab lets you specify the applet description and help hint. The description is the text that appears on the button face if you have the 'picture and text' property set for the GroupWise toolbar. The description also appears in any menu you integrate the applet with. The 'Help Hint' is the text that appears when the mouse pointer is held over a button in the GroupWise client, and when you select the menu integration you defined.

You should keep the description text short if you intend to use the GroupWise 'Picture and Text' option for toolbars. With this option set, GroupWise widens all its toolbar buttons to be the width of the longest button description. This can make the GroupWise buttons very untidy if you have long descriptions.

The Properties tab also lets you specify an image, from a supplied selection, to be displayed on the button. Formativ is supplied with a wide selection of general images.

You may edit the description, help hint and image associated with an applet at any time. However, you may have to restart the GroupWise client to see the changes take effect.


Adding Buttons to Toolbars

Formativ lets you add any number of buttons to most toolbars in the GroupWise client. For each button you define, Formativ lets you supply the text that appears on the button, the hint text that appears when you hold the mouse pointer over the button, and an image for the button.

As with all integrations, defining a button is context based. This means you can assign a button to appear with one or more GroupWise contexts. To define where the button should appear, select the Integrations tab within FormativCentral and select the context you wish to define the button within. For example, if you would like to add the button to the GroupWise main toolbar, double click the 'GroupWise Main Window' context, then double click the 'Toolbars' category. There is only one toolbar on the main menu, so check the 'main' option. The next time you start the GroupWise client, a button will appear on the main toolbar with the image, caption and help hint you defined. Clicking the button will execute the applet.

You can define any number of buttons that execute a single applet. For example, if you would also like to have the same button described above appear on the email dialog toolbar, double click the 'Mail' context, double click 'Toolbars', then check the 'main' check box. The GroupWise client will now have two new buttons that execute the same applet. One will appear on the main menu, another will appear on the email view dialog.


Adding Items to Context Menus

Formativ lets you add context menu (also known as right mouse click, floating or pop up menus) items to the GroupWise client. These items appear when you click the right mouse button over a particular item in the GroupWise client. For example, if you select an email message in a folder and press the right mouse button, a context menu appears that contains options specific to email items.

As with all integrations, defining a context menu item is context based. To define to which context menu an item should be added, select the Integrations tab within FormativCentral and select the context in which you wish to add the context menu item. For example, if you would like to add the item to the context menu that appears when you right mouse click over an email message, double click the 'Mail' context, then double click the 'Context Menus' category. There is only one context menu associated with email messages, so check the 'main' option. The next time you right mouse click over an email message, the context menu that appears will contain a new item with the caption and help hint you defined for the applet. Selecting the context menu item will execute the applet.

The context GroupWise uses can change depending where the mouse is when you right click. Be aware of this when defining context menu integrations. You may have to define several context menu integrations to have your applet accessible from all the menus that you require your new item to appear on.


Adding Items to Menus

Formativ lets you add any number of menu items to most top level menus in the GroupWise client. For each menu item you define, Formativ lets you supply the text that appears on the menu and the hint text that appears when you hold the mouse pointer over the menu item in the client.

As with all integrations, menu integrations are context based. This means you can assign a menu item to appear within one or more GroupWise contexts. To define where the menu item should appear, select the Integrations tab within FormativCentral and select the context you wish to define the menu item.

For example, if you would like to add the menu item to the GroupWise main menu under the File menu option, double click the 'GroupWise Main Window' context, then double click the 'Menus' category. Double click the menus option to expand all the top level menu items within the context. Locate the 'File' menu item, then double click it to show all the menu items under the 'File' menu. Select a menu item to act as an 'anchor', and press the right-mouse button. A menu appears that lets you add your new menu item either before or after the current item. The next time you start the GroupWise client, a menu item will appear on the GroupWise 'File' menu that executes your applet when selected.

You can define any number of menu items that execute a single applet. For example, if you would also like to have the same menu item as described above appear on the email dialog toolbar, double click the 'Mail' context, then follow the same directions above. The GroupWise client will now have two new menu items that execute the same applet. One will appear on the main menu, another will appear on the email view menu.


Associating applets with Events

Associating Applets with GroupWise Events

Formativ lets you execute an applet when particular GroupWise events occur, such as when the GroupWise client starts up, a new message appears in your mailbox, or when you send a new item.

There is a wide range of events you are able to associate applets with. Most of the events of interest are those associated with the GroupWise message contexts, such as 'Mail' and 'Appointments'. For example, Formativ lets you associate an applet with the 'On Send' event of all message types, giving you the capability to write applets that perform some action prior to a message being sent.

Events are given names starting with 'On', such as 'On Send', 'On Print' and 'On Open'.

When you subscribe to a particular event, the GroupWise processing that would normally occur is executed first, then your applet is executed. The only exception is the 'On Send' event, where your applet is executed, before the item is sent by GroupWise.

A future release of Formativ will let you control the order in which the original event is fired in relation to your applet. You will also be able to discard the original processing completely and replace the functionality with that contained in your applet. This will let you completely change the way many standard GroupWise features work, or disable them all together.

As with all integrations, associating an applet with a GroupWise event is context based. To define which event an applet should be associated with, select the Integrations tab within FormativCentral and select the context in which you wish to associate the event. For example, if you would like to run an applet when the user presses the 'Send' button after creating a new email message, double click the 'Mail' context, then double click the 'Events' category. Locate the 'On Send' check box and select it. The next time the email send button is pressed, the applet will be executed.

You can associate a single applet with multiple events within the same context, or with multiple events within different contexts. For example, you might associate a single applet with the 'On Compose' and 'On Reply' events of all the message types.

Take care when associating applets with events. While it is technically possible to associate an applet with any supported events, try to limit the intrusion of your applet onto events as much as possible. Some applets lend themselves to association with events more than others. For example, while it makes good sense to associate a signatures or disclaimer applet with the 'On Send' event, other applets may not lend themselves as favorably.

Adding Applets to the Formativ 'Favorites' Menu

This version of Formativ adds a 'Applets' menu to the main GroupWise menu. You can have any applet appear on this menu for easy and quick access.

To add an applet to the Applets menu, select the Properties tab within FormativCentral and check the 'Appear on favorites menu in GroupWise' check box. The next time you start the GroupWise client, a new menu item will appear on the Formativ menu that executes the appropriate applet.


Error Handling and Debugging

Types of Applet Errors and How to Fix them

There are essentially two main types of applet errors: syntax errors and runtime errors.

Syntax errors are fundamental problems in your applet that cause the applet not to run.

Runtime errors are problems with your applet that only appear under particular circumstances. For example, if your applet attempts to access the services of a COM server (such as Microsoft Word) that is not installed on a particular PC, a runtime error will occur when your applet attempts to create the service. Runtime errors are often more difficult to detect as they are often environment sensitive.

Syntax Errors

Syntax errors are usually detected while developing applets. When you attempt to execute your applet, a message box appears stating the applet cannot be executed, and the reason why. The error dialog will also indicate the line number in the source code where the error occurred.

To fix a syntax error, locate the offending line of code and examine the syntax used. You may have to refer to the language documentation to determine the correct syntax.

Some things to be aware of when debugging syntax errors:

If the error is not obvious in the row indicated by the error message, look at the lines just above or below the indicated row. An error reported to be at a particular location is sometimes caused by a syntax error just above or below the given location.

Be careful in your use of parentheses when calling a function. See the Visual Basic Script language documentation for more details.

If a function call syntax fails, try calling the function with the Call keyword.

Runtime Errors

Runtime errors might occur at some point while running an applet. Runtime errors occur when a syntactically correct piece of code fails for some reason. These errors can often be more difficult to solve because they might only occur on certain machines or under certain circumstances.

The key to debugging runtime errors is to replicate the steps taken to induce the failure. If reproducing the steps taken to run the applet does not force the error, you may need to check if the applet is attempting to use any resources that are not installed on the target machine, such as COM services or other resources.

Defensive Programming

The best way to avoid runtime errors in your applets is to employ defensive programming strategies. Never assume a particular service will be available, and never assume that every call you make will succeed.

For example, if your applet uses third party COM services such as Microsoft Word or Excel, you should check that you were able to create an instance of the COM object before actually using its services. This usually means using the On Error statement, followed by checks to confirm your request for a particular service was successful. In the example below, a defensive attempt is made to use services in Microsoft Word. This code will not cause a runtime error if Word does not exist on the target PC, or some other error occurred:

     CheckWord = TRUE

     ' Resume with the next line following the error.
     On Error Resume Next

     ' Attempt to reference Word, which is already running.
     Set Word = GetObject(, "Word.Application")

     ' If true, Word is not running.
     if Word Is Nothing Then

           ' Create a new instance of the Word application.
           Set Word = CreateObject("Word.Application")

           ' If true, MS Word 8.0 is not installed.
           if Word Is Nothing Then
                 MsgBox "MS Word is not installed on your computer."
           End If

      End If


Creating new toolbar images

Formativ ships with a large number of images you can choose to assign to your applets. However, there may be times when you would like to use an image that is not included with the product.

Creating a new image to use with Formativ is a three step process:

Create a 16 by 16 pixel bitmap and draw your image

Add the image to a library in Formativ

Distribute the library to all users who require the new image

Please note that adding a new image to Formativ is a technical process and requires developer tools. You should only attempt to create new images if you are familiar with using developer tools. Please consult your IT department if you are in doubt.

Step 1 - Create a new bitmap

Create a new bitmap file. The bitmap must be 16 pixels high by 16 pixels wide. It must use the 16 color Windows palette. Fill the entire bitmap with green (RGB 0, 255, 0). This green color is used by GroupWise to represent transparent areas. Any green area will be transparent when the image is drawn on a button in GroupWise. Once you have filled the bitmap with green you may start drawing your image using the standard 16 color Windows palette.

Save your bitmap file when you are satisfied with the results.

Step 2 - Add the image to a Formativ Library

In order to make your bitmap available, you must add it to a Formativ image library. An image library is a resource DLL that contains nothing other than bitmap images. Formativ ships with a number of different image library files. They are named using the category of image they represent, and all have the extension .DLI. Technically, adding a new image to an image library involves adding a new bitmap resource to a DLL.

The exact steps you take to add a new bitmap to an image library varies based on the tool you will use. The following steps are based on using Microsoft Visual Studio 6.0, but you can use most modern Windows development tools.

Start Microsoft Visual Studio 6

Select File | Open. When the open dialog appears, change the Open As combo box selection to be Resources

Browse to where the .DLI is located into which you wish to add the new image. This is the same location where Formativ was installed

Select the appropriate .DLI and select Open

When the file opens, select the Bitmap node of the display, right mouse click and select Import...

When the Import Resource dialog appears, browse to the location of your new bitmap file. You may have to change the file type selection to *.bmp in order to see bitmaps. Select the bitmap and press Import

The bitmap has now been added to the .DLI file. Press CTRL+S to save your work, then exit Visual Studio.

The image is now available to Formativ. Simply re-start GroupWise if running and the image should appear in the list of available images.

Step 3 - Distribute the new library

Should you wish other Formativ users to have access to your updated image library, you must make it available to them. To make the image library available, simply copy the appropriate .DLI file into each user's Formativ directory. Each user will have to re-start GroupWise in order to see the new image in FormativCentral.


Differences between HTML Dialogs and Portals